/** * Squidy Interaction Library is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License as * published by the Free Software Foundation, either version 3 of the License, * or (at your option) any later version. * * Squidy Interaction Library is distributed in the hope that it will be * useful, but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with Squidy Interaction Library. If not, see * <http://www.gnu.org/licenses/>. * * 2009 Human-Computer Interaction Group, University of Konstanz. * <http://hci.uni-konstanz.de> * * Please contact info@squidy-lib.de or visit our website * <http://www.squidy-lib.de> for further information. */ package org.squidy.nodes.laserpointer; import gnu.io.CommPortIdentifier; import gnu.io.SerialPort; import gnu.io.SerialPortEvent; import gnu.io.SerialPortEventListener; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.util.Enumeration; import java.util.StringTokenizer; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.squidy.manager.data.impl.DataButton; import org.squidy.manager.data.impl.DataDigital; import org.squidy.manager.data.impl.DataInertial; import org.squidy.nodes.Laserpointer; /** * @author Werner Koenig, werner.koenig@uni-konstanz.de, University of Konstanz */ public class WirelessLaserDriver extends Thread implements SerialPortEventListener, LaserVibrate { /** * Logger to log info, error, debug,... messages. */ private static final Log LOG = LogFactory.getLog(WirelessLaserDriver.class); private static final int THRESHOLD = -100000; private String delimiter = ";"; private Laserpointer laserPointer = null; private static CommPortIdentifier portId; private static Enumeration portList; private InputStream inputStream; private SerialPort serialPort; private OutputStream outputStream; private String bufferInLine = ""; private int discardPackets = 25; private int firstToken = 2; private int firstTokenCounter = firstToken; private byte[] readBuffer = new byte[200]; private StringTokenizer line, toker; private boolean greenFront = true; private boolean greenBack = true; private boolean redFront = true; private boolean redBack = true; private boolean isVibrating = false; private boolean toggle = true; private LaserVibration laserVibration; private int alarmReset = 5;// property-file private int alarmCounter = alarmReset; private int reconnectLoop = 100; private int stopReconnectLoop = -1200; private boolean alarmed = false; private boolean connected = true; private boolean running = true; private boolean isConfig = false; private String[] mac_srv = { "01", "03", "05" }; private String[] mac_lp = { "02", "04", "06" }; private int currSerNo = 0; private double acc_a_zero, acc_b_zero, acc_c_zero; private double acc_a_1, acc_b_1, acc_c_1; private double acc_a_2, acc_b_2, acc_c_2; private double acc_a_3, acc_b_3, acc_c_3; // private FileOutputStream fos = null; public WirelessLaserDriver(Laserpointer laserPointer, String port) { // try { // fos = new FileOutputStream("serial-bytes"); // } catch (FileNotFoundException e) { // // TODO Auto-generated catch block // e.printStackTrace(); // } // boolean portFound = false; laserPointer = laserPointer; // parse ports and if the default port is found, initialized the reader portList = CommPortIdentifier.getPortIdentifiers(); while (portList.hasMoreElements()) { portId = (CommPortIdentifier) portList.nextElement(); if (portId.getPortType() == CommPortIdentifier.PORT_SERIAL) { if (portId.getName().equals(port)) { if (LOG.isInfoEnabled()) { LOG.info("Found port: " + port); } portFound = true; if (initStream()) { initAlarm(); currSerNo = laserPointer.getSerialNumber(); start(); // LaserDriverTestZKM t = new LaserDriverTestZKM(); break; } } } } if (!portFound) { if (LOG.isErrorEnabled()) { LOG.error("port " + port + " not found."); } } } public boolean initStream() { // initalize serial port try { serialPort = (SerialPort) portId.open("LaserDriver", 2000); inputStream = serialPort.getInputStream(); // serialPort.addEventListener(this); // activate the DATA_AVAILABLE notifier // serialPort.notifyOnDataAvailable(true); // set port parameters serialPort.setSerialPortParams(19200, SerialPort.DATABITS_8, SerialPort.STOPBITS_1, SerialPort.PARITY_NONE); // get the outputstream outputStream = serialPort.getOutputStream(); // activate the OUTPUT_BUFFER_EMPTY notifier // serialPort.notifyOnOutputEmpty(true); // if (laserPointer.isRestartLaserPointerExe()) { // try { // Runtime.getRuntime().exec( // "cmd.exe /c start /MIN resetLP.exe 10"); // } catch (IOException e) { // LOG.error("Couldn't start the batch file."); // } // } return true; } catch (Exception e) { if (LOG.isErrorEnabled()) { LOG.error("Error setting serial connection"); } return false; } } private void initAlarm() { alarmReset = laserPointer.getWaitForAlarm(); new Thread() { public void run() { while (running) { try { sleep(100); } catch (InterruptedException e) { } if (--alarmCounter < 0 && connected) { // alarm laserPointer.publish(new DataDigital(laserPointer .getClass(), true)); connected = false; alarmed = true; bufferInLine = ""; firstTokenCounter = firstToken; if (LOG.isErrorEnabled()) { if (LOG.isErrorEnabled()) { LOG.error("Laserpointer not reachable"); } } isVibrating = false; DataDigital data = new DataDigital(laserPointer .getClass(), true); laserPointer.publish(data); } // System.out.println(alarmCounter); if (!connected && alarmed && alarmCounter > stopReconnectLoop && alarmCounter < 0 && (alarmCounter % reconnectLoop == 0)) { // System.out.println("RESET"); DataDigital data = new DataDigital(laserPointer .getClass(), true); laserPointer.publish(data); } if (connected && alarmed) { laserPointer.publish(new DataDigital(laserPointer .getClass(), false)); alarmed = false; if (LOG.isErrorEnabled()) { LOG.info("Laserpointer reconnected"); } vibrate(false, 0); } if (alarmCounter < THRESHOLD) { alarmCounter = THRESHOLD; } } } }.start(); } public synchronized 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: // case SerialPortEvent.OUTPUT_BUFFER_EMPTY: // break; // case SerialPortEvent.DATA_AVAILABLE: // try { // readInput(); // // jbReadInput(); // } catch (IOException e) { // logger.error("Connection error occured (Receiving)."); // DataDigital data = new DataDigital(lp.getClass(),"RESET-LP", true); // lp.pushSample(data); // } // break; // } } // public void jbReadInput() throws IOException { // ByteArrayOutputStream baos = new ByteArrayOutputStream(); // byte[] bytes = new byte[300]; // while(inputStream.available() > 0) { // int bytesRead = inputStream.read(bytes); // baos.write(bytes, 0, bytesRead); // } // fos.write(baos.toByteArray()); // fos.flush(); // } // private String readSerial() throws IOException { // // String result = ""; // // while (inputStream.available() > 0) { // // //int bytesRead = inputStream.read(readBuffer); // // // ByteArrayOutputStream baos = new ByteArrayOutputStream(); // // baos.write(readBuffer, 0, bytesRead-1); // // fos.write(baos.toByteArray()); // // for (int i = 0; i < readBuffer.length; i++) { // readBuffer[i] = '_'; // } // inputStream.read(readBuffer); // for (int i = 0; i < readBuffer.length; i++) { // if (readBuffer[i] == 0 || (readBuffer[i] & 0x80) > 0) { // readBuffer[i] = '_'; // } // } // result += new String(readBuffer); // //System.out.println("."); // } // result = removeEmptySpaces(result); // // fos.flush(); // // //System.out.println("..."+result+" "+result.getBytes().length); // // return result; // } public void run() { int len = -1; String result = ""; for (int i = 0; i < readBuffer.length; i++) { readBuffer[i] = '_'; } while (running) { try { while ((len = this.inputStream.read(readBuffer)) > 0 && running) { if (len > 0) { // Calendar c = Calendar.getInstance(); // System.out.println("buffer:"+new String(readBuffer)); alarmCounter = alarmReset; if (!connected) { bufferInLine = ""; connected = true; updateStatus(); continue; } for (int i = 0; i < readBuffer.length; i++) { if (readBuffer[i] == 0 || (readBuffer[i] & 0x80) > 0) { readBuffer[i] = '_'; } } result = removeEmptySpaces(new String(readBuffer)); for (int i = 0; i < readBuffer.length; i++) { readBuffer[i] = '_'; } if (isConfig) { System.out.println("Received: " + result); continue; } // System.out.println(bufferInLine+"----"+result); if (discardPackets < 0) { bufferInLine = bufferInLine + result; parseStatus(); } else { discardPackets--; bufferInLine = ""; } // System.out.println(c.getTimeInMillis()); } try { sleep(4); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } catch (IOException e) { if (LOG.isErrorEnabled()) { LOG.error("Connection error occured."); } } } } // private synchronized void readInput() throws IOException { // alarmCounter = alarmReset; // if(!connected){ // bufferInLine = ""; // connected = true; // updateStatus(); // return; // } // // String result = readSerial(); // // if(result.length()==0) return; // // if(isConfig){ // System.out.println("Received: "+result); // return; // } // // if (discardPackets < 0) { // bufferInLine = bufferInLine + result; // parseStatus(); // } else { // discardPackets--; // } // } private String removeEmptySpaces(String str) { for (int i = str.length() - 1; i >= 0; i--) { if (str.charAt(i) == '_') { str = str.substring(0, i) + str.substring(i + 1, str.length()); } } return str; } private void parseStatus() { if (bufferInLine.indexOf("\r") == -1 || bufferInLine.length() < 38) { return; } // System.out.println(bufferInLine); line = new StringTokenizer(bufferInLine, "\r"); String token, butHex; String leftOver = ""; while (line.hasMoreTokens()) { token = line.nextToken(); // System.out.println(token); toker = new StringTokenizer(token, delimiter); if (toker.countTokens() == 10 && token.length() == 38) { butHex = toker.nextToken(); int butBin = Integer.parseInt(butHex, 16); toker.nextToken(); toker.nextToken(); toker.nextToken(); toker.nextToken(); toker.nextToken(); toker.nextToken(); double raw_a = Integer.parseInt(toker.nextToken(), 16); // Sensor_Z, // Wii_-Y double raw_b = Integer.parseInt(toker.nextToken(), 16); // Sensor_X, // Wii_-Z double raw_c = Integer.parseInt(toker.nextToken(), 16); // Sensor_Y, // Wii_X // System.out.println(a+"("+raw_a+") "+b+"("+raw_b+") // "+c+"("+raw_c+") "); if (firstTokenCounter < 0) { laserPointer.publish(new DataInertial(laserPointer .getClass(), raw_a, raw_b, raw_c, true)); laserPointer.publish(new DataButton(Laserpointer.class, DataButton.BUTTON_1, !((butBin & 0x2) > 0))); laserPointer.publish(new DataButton(Laserpointer.class, DataButton.BUTTON_2, !((butBin & 0x10) > 0))); laserPointer.publish(new DataButton(Laserpointer.class, DataButton.BUTTON_3, !((butBin & 0x4) > 0))); } else { firstTokenCounter--; // System.out.println("ignore"); } } else { if (line.countTokens() == 0 && token.length() < 38) { leftOver = token; } else { if (LOG.isErrorEnabled()) { LOG.error("Wrong token size: " + toker.countTokens() + " " + token); } } } } bufferInLine = leftOver; } public void vibrate(boolean vibrate, final int duration) { if (laserVibration != null) { laserVibration.cancel(); } // if(isVibrating!=vib){ isVibrating = vibrate; updateStatus(); // } if (duration > 0) { laserVibration = new LaserVibration(this, duration); } } public void setGreenLED(boolean green) { greenBack = green; greenFront = green; updateStatus(); } public void setRedLED(boolean red) { redFront = red; redBack = red; updateStatus(); DataDigital data = new DataDigital(laserPointer.getClass(), true); laserPointer.publish(data); } public void setLEDColor(boolean red, boolean green) { redFront = red; redBack = red; greenBack = green; greenFront = green; updateStatus(); } private synchronized void updateStatus() { if (!connected) return; try { toggle = !toggle; int t = (toggle) ? 1 : 0; int v = (isVibrating) ? 1 : 0; int rf = (redFront) ? 0 : 1; int rb = (redBack) ? 0 : 1; int gf = (greenFront) ? 0 : 1; int gb = (greenBack) ? 0 : 1; int res = 0; if (currSerNo == 1) res = (gf * 1) | (rf * 2) | (gb * 4) | (0 * 8) | (rb * 16) | (t * 32) | (v * 64) | (1 * 128); if (currSerNo == 0) res = (rf * 1) | (gf * 2) | (0 * 4) | (rb * 8) | (t * 16) | (gb * 32) | (v * 64) | (1 * 128); if (outputStream != null) { outputStream.write(res & 0xff); outputStream.flush(); } } catch (IOException e) { if (LOG.isErrorEnabled()) { LOG.error("Connection error occured (Update)."); } } } public void updateMAC() { isConfig = true; currSerNo = laserPointer.getSerialNumber(); if (LOG.isInfoEnabled()) { LOG.info("ChangeMAC"); } try { writeSerial("+++"); try { Thread.sleep(100); } catch (InterruptedException e) { } writeSerial("ats4="); try { Thread.sleep(100); } catch (InterruptedException e) { } writeSerial("00-"); try { Thread.sleep(100); } catch (InterruptedException e) { } writeSerial("15-"); try { Thread.sleep(100); } catch (InterruptedException e) { } writeSerial("20-"); try { Thread.sleep(100); } catch (InterruptedException e) { } writeSerial("00-"); try { Thread.sleep(100); } catch (InterruptedException e) { } writeSerial("00-"); try { Thread.sleep(100); } catch (InterruptedException e) { } writeSerial("00-"); try { Thread.sleep(100); } catch (InterruptedException e) { } writeSerial("00-"); try { Thread.sleep(100); } catch (InterruptedException e) { } writeSerial(mac_srv[currSerNo]); try { Thread.sleep(100); } catch (InterruptedException e) { } writeSerial("\r\n"); try { Thread.sleep(100); } catch (InterruptedException e) { } writeSerial("ats5="); try { Thread.sleep(100); } catch (InterruptedException e) { } writeSerial("00-"); try { Thread.sleep(100); } catch (InterruptedException e) { } writeSerial("15-"); try { Thread.sleep(100); } catch (InterruptedException e) { } writeSerial("20-"); try { Thread.sleep(100); } catch (InterruptedException e) { } writeSerial("00-"); try { Thread.sleep(100); } catch (InterruptedException e) { } writeSerial("00-"); try { Thread.sleep(100); } catch (InterruptedException e) { } writeSerial("00-"); try { Thread.sleep(100); } catch (InterruptedException e) { } writeSerial("00-"); try { Thread.sleep(100); } catch (InterruptedException e) { } writeSerial(mac_lp[currSerNo]); try { Thread.sleep(100); } catch (InterruptedException e) { } writeSerial("\r\n"); try { Thread.sleep(100); } catch (InterruptedException e) { } writeSerial("at0\r\n"); try { Thread.sleep(100); } catch (InterruptedException e) { } } catch (IOException e1) { if (LOG.isErrorEnabled()) { LOG.error("Connection error occured (MAC)."); } } finally { isConfig = false; } } private synchronized void writeSerial(String str) throws IOException { // logger.debug("write serial "+str); if (outputStream != null && connected) { outputStream.write(str.getBytes()); outputStream.flush(); } } public void close() { // try { // fos.close(); // TODO: DEBUG jb // } catch (IOException e1) { // // TODO Auto-generated catch block // e1.printStackTrace(); // } if (LOG.isInfoEnabled()) { LOG.info("Close serial connection"); } running = false; try { inputStream.close(); outputStream.close(); } catch (Exception e) { if (LOG.isErrorEnabled()) { LOG.error("Couldn't close socket"); } } if (laserVibration != null) { laserVibration.cancel(); } serialPort.close(); } }