// 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.in; import java.io.IOException; import java.util.ArrayList; import java.util.List; import pleocmd.Log; import pleocmd.cfg.ConfigDouble; import pleocmd.cfg.ConfigInt; import pleocmd.exc.ConfigurationException; import pleocmd.exc.InputException; import pleocmd.pipe.data.Data; import pleocmd.pipe.data.SingleBoolData; public final class IdleInput extends Input { // NO_UCD private final ConfigDouble cfgProbability; private final ConfigInt cfgDelayIdle; private final ConfigInt cfgDelayRepeat; private final ConfigInt cfgPriority; private final ConfigInt cfgUserData; private boolean first; private long last; public IdleInput() { addConfig(cfgProbability = new ConfigDouble("Probability", 0.75, 0, 1)); addConfig(cfgDelayIdle = new ConfigInt("Idle-Delay", 4000, 0, Integer.MAX_VALUE)); addConfig(cfgDelayRepeat = new ConfigInt("Repeat-Delay", 1000, 10, Integer.MAX_VALUE)); addConfig(cfgPriority = new ConfigInt("Priority", Data.PRIO_LOWEST + (Data.PRIO_DEFAULT - Data.PRIO_LOWEST) / 2, Data.PRIO_LOWEST, Data.PRIO_DEFAULT - 1)); addConfig(cfgUserData = new ConfigInt("UserData", 0)); constructed(); } public IdleInput(final double probability, final int delayIdle, final int delayRepeat, final int priority, final int userData) throws ConfigurationException { this(); cfgProbability.setContent(probability); cfgDelayIdle.setContent(delayIdle); cfgDelayRepeat.setContent(delayRepeat); cfgPriority.setContent(priority); cfgUserData.setContent(userData); } @Override public String getOutputDescription() { return "bool"; } @Override protected String getShortConfigDescr0() { return String.format("[P%02d] %dms + %dms * %.2f", cfgPriority.getContent(), cfgDelayIdle.getContent(), cfgDelayRepeat.getContent(), cfgProbability.getContent()); } @Override protected void init0() throws InputException, IOException { first = true; } @Override protected Data readData0() throws InputException, IOException { if (first) { // we've been called from the main input thread first = false; // create a second input thread with only this instance as an input final List<Input> l = new ArrayList<Input>(); l.add(this); getPipe().createNewInputThread(l).start(); // don't do anything in this thread - just signal "finished" return null; } // as we only create background data, we should exit // ourself once the main input thread has been closed. if (getPipe().isMainInputThreadFinished()) { Log.info("Ending Idle-Input as Main-Input-Thread closed"); return null; } try { final long now = System.currentTimeMillis(); final long next = last + cfgDelayRepeat.getContent(); if (next > now) { Log.detail("Artificially slow down by %d ms", next - now); Thread.sleep(next - now); } } catch (final InterruptedException e) { Log.detail("Slow down interrupted"); return null; } last = System.currentTimeMillis(); final long idle = last - getPipe().getFeedback().getLastNormalDataOutput(); return new SingleBoolData(idle > cfgDelayIdle.getContent() && Math.random() < cfgProbability.getContent(), cfgUserData.getContent(), null, cfgPriority.getContent() .byteValue(), Data.TIME_NOTIME); } public static String help(final HelpKind kind) { switch (kind) { case Name: return "Idle Input"; case Description: return "Creates boolean Data blocks while the Pipe is idle"; case Config1: return "Probability to send 'true' instead of 'false' in the Data blocks"; case Config2: return "Number of ms the pipe must be idle before sending " + "the first Data block"; case Config3: return "Number of ms between two Data blocks while the Pipe is idle"; case Config4: return "Priority of all sent Data Blocks"; case Config5: return "Some Integer which is sent as an additional argument in " + "the Data blocks (mostly used for channel number)"; default: return null; } } @Override public String isConfigurationSane() { return null; } @Override protected int getVisualizeDataSetCount() { return 0; } }