// This file is part of PleoCommand: // Interactively control Pleo with psychobiological parameters // // Copyright (C) 2010 Oliver Hoffmann - Hoffmann_Oliver@gmx.de // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program 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 General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program; if not, write to the Free Software // Foundation, Inc., 51 Franklin Street, Boston, USA. package pleocmd.pipe.out; import gnu.io.CommPortIdentifier; import java.awt.EventQueue; import java.io.IOException; import java.util.ArrayList; import java.util.List; import java.util.StringTokenizer; import java.util.concurrent.TimeoutException; import pleocmd.Log; import pleocmd.StringManip; import pleocmd.api.PleoCommunication; import pleocmd.cfg.ConfigItem; import pleocmd.exc.ConfigurationException; import pleocmd.exc.OutputException; import pleocmd.itfc.gui.MainFrame; import pleocmd.pipe.data.CommandData; import pleocmd.pipe.data.Data; public final class PleoRXTXOutput extends Output { private final ConfigItem<String> cfgDevice; private PleoCommunication pc; private Thread thrUpdateStatusLabel; public PleoRXTXOutput() { ConfigItem<String> tmp; try { tmp = new ConfigItem<String>("Device", "", getAllDeviceNames()); } catch (final UnsatisfiedLinkError e) { Log.error(e, "Cannot find external library in '%s'", System.getProperty("java.library.path")); tmp = new ConfigItem<String>("Device", "", new ArrayList<String>()); } addConfig(cfgDevice = tmp); constructed(); } public PleoRXTXOutput(final String device) throws ConfigurationException { this(); cfgDevice.setContent(device); } private static List<String> getAllDeviceNames() { final List<String> names = new ArrayList<String>(); try { final List<CommPortIdentifier> ports = PleoCommunication .getAvailableSerialPorts(); for (final CommPortIdentifier port : ports) names.add(port.getName()); } catch (final NoClassDefFoundError e) { Log.error(e, "RXTX not available"); } return names; } @Override protected void init0() throws IOException, OutputException { Log.detail("Initializing PleoRXTXOutput for device '%s'", cfgDevice.getContent()); try { pc = new PleoCommunication(PleoCommunication.getPort(cfgDevice .getContent())); } catch (final NoClassDefFoundError e) { throw new OutputException(this, true, e, "RXTX not available"); } pc.init(); thrUpdateStatusLabel = new Thread() { @Override public void run() { while (isThrUpdateStatusLabel()) { try { final String res; synchronized (PleoRXTXOutput.this) { if (!MainFrame.hasGUI() || !isThrUpdateStatusLabel()) break; getPC().send("STATS POWER"); res = getPC().readAnswer(); } final StringTokenizer lineTok = new StringTokenizer( res, "\n\r"); String power = "???"; while (lineTok.hasMoreTokens()) { final String line = lineTok.nextToken(); if (line.contains("Battery sensor value")) { final int idx1 = line.indexOf("="); if (idx1 != -1) { power = line.substring(idx1 + 1); final int idx2 = power.indexOf("("); if (idx2 != -1) power = power.substring(0, idx2); } break; } } final String powerFinal = String.format( "Battery: %s%%", power.trim()); EventQueue.invokeLater(new Runnable() { @Override public void run() { MainFrame.the().updateStatusLabel( PleoRXTXOutput.this, powerFinal); } }); } catch (final TimeoutException e) { MainFrame.the().updateStatusLabel(PleoRXTXOutput.this, "ERROR"); } catch (final IOException e) { MainFrame.the().updateStatusLabel(PleoRXTXOutput.this, "ERROR"); } try { Thread.sleep(5000); } catch (final InterruptedException e1) { break; } } EventQueue.invokeLater(new Runnable() { @Override public void run() { MainFrame.the().updateStatusLabel(PleoRXTXOutput.this, ""); } }); } }; thrUpdateStatusLabel.setDaemon(true); thrUpdateStatusLabel.start(); } protected synchronized boolean isThrUpdateStatusLabel() { return thrUpdateStatusLabel != null; } protected PleoCommunication getPC() { return pc; } @Override protected void close0() { Log.detail("Closing PleoRXTXOutput '%s' for device '%s'", pc, cfgDevice.getContent()); synchronized (this) { pc.close(); pc = null; thrUpdateStatusLabel.interrupt(); thrUpdateStatusLabel = null; } } @Override public String getInputDescription() { return "PMC"; } @Override protected String getShortConfigDescr0() { return cfgDevice.getContent(); } @Override protected boolean write0(final Data data) throws OutputException, IOException { if (!CommandData.isCommandData(data, "PMC")) return false; synchronized (this) { if (Log.canLogInfo()) Log.info("<html>Sent to Pleo: " + StringManip.printSyntaxHighlightedAscii(data)); pc.send(CommandData.getArgument(data)); try { Log.consoleOut(pc.readAnswer()); } catch (final TimeoutException e) { throw new OutputException(this, true, e, "Cannot read answer for command '%s'", data); } } return true; } public static String help(final HelpKind kind) { // NO_UCD switch (kind) { case Name: return "Pleo RXTX Output"; case Description: return "Processes commands like 'PMC|foo' by sending 'foo' " + "without any modifications to the Pleo via an USB " + "connection by using the RXTX library"; case Config1: return "Path to the device on which the Pleo is connected to " + "this computer"; default: return null; } } @Override public String isConfigurationSane() { try { PleoCommunication.getPort(cfgDevice.getContent()); } catch (final NoClassDefFoundError e) { return "RXTX not available"; } catch (final IOException e) { return String.format("Device '%s' does not exist", cfgDevice.getContent()); } return null; } @Override protected int getVisualizeDataSetCount() { return 0; } }