/* * Copyright 2013 Ytai Ben-Tsvi. All rights reserved. * * * Redistribution and use in source and binary forms, with or without modification, are * permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, this list of * conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, this list * of conditions and the following disclaimer in the documentation and/or other materials * provided with the distribution. * * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL ARSHAN POURSOHI OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * The views and conclusions contained in the software and documentation are those of the * authors and should not be interpreted as representing official policies, either expressed * or implied. */ package ioio.lib.api; import ioio.lib.api.exception.ConnectionLostException; /** * A waveform sequencer. * <p/> * The {@link Sequencer} interface enables generation of very precisely-timed digital waveforms, * primarily targeted for different kinds of actuators, such as different kinds of motors, solenoids * and LEDs. The output comprises one or more channels, each of which can have one of several * different types. The output channels type and their assignments to pins are determined when the * {@link Sequencer} instance is created and cannot be changed during its lifetime. A * {@link Sequencer} instance is obtained via {@link IOIO#openSequencer(ChannelConfig[])}. * <p/> * Each channel is configured with one of the {@link ChannelConfig} subclasses. For example, * {@link ChannelCueBinary} specified a binary output, useful for controlling an LED or a solenoid. * This configuration includes, among other things, the pin specification for this channel. See the * individual subclasses documentation for more information. * <p/> * Once instantiated, the {@link Sequencer} gets fed with a stream of <cue, duration> pairs. A * cue is a set of instructions telling each of the channels what to do, or more precisely, one * {@link ChannelCue} per channel. The concrete type of the {@link ChannelCue} depends on the * channel type, for example, a channel that has been configured with {@link ChannelConfigBinary}, * expects a {@link ChannelCueBinary} for its cue. In this example, the cue will specify whether * this output should be high or low. When a cue is combined with a duration, it has the semantics * of "for this much time, generate this waveform". A stream of such pairs can represent a complex * multi-channel waveform. * <p/> * The above <cue, duration> pairs are pushed into the {@link Sequencer} via the * {@link #push(ChannelCue[], int)} method. They will not yet be executed, but rather queue up. * There is a limited number of cues that can be queued. Attempting to push more will block until a * cue has been executed. In order to avoid blocking (especially during the initial fill of the * queue - see below), the {@link #available()} method returns the number of pushes that can be done * without blocking. Once a few of them have been queued up, execution may start by calling * {@link #start()} . During execution, more cues can be pushed, and ideally fast enough so that * execution never needs to stall. During execution, {@link #pause()} will suspend execution as soon * as the currently executed cue is done, without clearing the queue of pending cues. Operation can * then be resumed by calling {@link #start()} again. Calling {@link #stop()} will immediately stop * execution and clear the queue. Execution progress can be tracked at any time by calling * {@link #numCuesStarted()}, which will increment every time actual execution of a cue has begun. * It will be reset back to 0 following a {@link #stop()}. * <p/> * <h4>Pre-fill</h4> * In order to avoid stalls immediately after {@link #start()}, it is recommended to pre-fill the * cue FIFO priorly. The recommended sequence of operations is: * <p/> * <pre> * // Open the sequencer. * Sequencer s = ioio_.openSequencer(...); * // At this point, the FIFO might still be at zero capacity, wait until opening is complete. * s.waitEventType(Sequencer.Event.Type.STOPPED); * // Now our FIFO is empty and at full capacity. Fill it entirely. * while (s.available() > 0) { * s.push(...); * } * // Now we can start! * s.start(); * </pre> * <p/> * <h4>Manual Operation</h4> * In some cases it is useful to be able to execute some cues while the {@link Sequencer} is paused * or stopped without having to clear the queue. For this purpose, the * {@link #manualStart(ChannelCue[])} command can be used. Calling it will immediately begin * execution of a given cue, without changing the queue previously given. Unlike cues scheduled via * {@link #push(ChannelCue[], int)}, these cues have no duration, and will keep executing until * {@link #manualStop()} is called. After that, normal operation can be resumed by calling * {@link #start()} again. * <p/> * <h4>States</h4> * This table summarizes the different states the {@link Sequencer} can be in, and the methods which * can be called to change it: * <table border="1"> * <tr> * <th>Current State</th> * <th>Method</th> * <th>Next State</th> * </tr> * <tr> * <td rowspan="4">Idle</td> * <td>{@link #start()}</td> * <td>Running</td> * </tr> * <tr> * <td>{@link #manualStart(ChannelCue[])}</td> * <td>Manual</td> * </tr> * <tr> * <td>{@link #stop()}</td> * <td>Idle (and clear the queue)</td> * </tr> * <tr> * <td>{@link #manualStop()}</td> * <td>Idle (no-op)</td> * </tr> * <tr> * <td rowspan="2">Running</td> * <td>{@link #pause()}</td> * <td>Idle</td> * </tr> * <tr> * <td>{@link #stop()}</td> * <td>Idle (and clear the queue)</td> * </tr> * <tr> * <td rowspan="3">Manual</td> * <td>{@link #manualStop()}</td> * <td>Idle</td> * </tr> * <tr> * <td>{@link #stop()}</td> * <td>Idle (and clear the queue)</td> * </tr> * <tr> * <td>{@link #manualStart()}</td> * <td>Manual (new cue)</td> * </tr> * </table> * <p/> * <h4>Clocking</h4> * All the timing information provided to a single channel is based on a clock which implies a * time-base. For some channel types, the clock is determined upon instantiation; for others it can * be set on a per-cue basis. Once a clock rate is set, all timing values used for that channel are * in units of this time-base. Using a faster clock rate enables faster waveforms to be generated as * well as have better timing resolution for everything. However, since most timing values used in * this API have a limited range, using a faster clock would also limit the maximum duration of some * signals. As a rule of thumb, choosing the highest possible clock rate that can satisfy the * duration requirements is the right choice. * <p/> * <h4>Stalls</h4> * It is possible that the client does not push cues fast enough to keep up with execution. In that * case, the queue will drain and execution will stall. All channel types have well-defined * behaviors in case of a stall, for example, a binary channel allows the user to explicitly * determine whether it should be go back to its initial value or retain the current value when * stalled. Once stalled, as soon as a new cue gets pushed, operation will resume immediately * without having to call {@link #start()}. * <p/> * <h4>Keeping track of execution</h4> * Since execution of queued events is asynchronous, it is sometimes required to track their * execution progress, for example, for keeping a user interface synchronized with the actual state * of a multi-axis machine. * <p/> * The client can poll for the last event that occured via {@link #getLastEvent()}, or block until * the next one arrives using {@link #waitEvent()}. The latter features a limited-size queue, so * events are not lost as long as the client reads continuously. The queue is initially 32-events * long, but could be changed using {@link #setEventQueueSize(int)}. The sequencer will report the * following kinds of events, via the {@link Event} type: * <dl> * <dt>STOPPED</dt> * <dd>The sequencer has been stopped (and the cue FIFO is now empty). This is also the event that * is returned when calling {@link #getLastEvent()} before any event has arrived.</dd> * <dt>CUE_STARTED</dt> * <dd>A new cue has just started execution.</dd> * <dt>PAUSED</dt> * <dd>A cue has just finished execution and progress has been paused as result of an explicit pause * request.</dd> * <dt>STALLED</dt> * <dd>A cue has just finished execution and progress has been paused as result of the queue running * empty. In this case, the state of the sequencer does not change (i.e. it is still Running), and * pushing addition events will immediately resume execution.</dd> * <dt>CLOSED</dt> * <dd>The sequencer has been closed. This is mostly intended for gracefully exiting a thread which * is constantly blocking on {@link #waitEvent()}</dd> * </dl> * <p/> */ public interface Sequencer extends Closeable { /** * A clock rate selection, which implies a time-base. */ public enum Clock { /** * 16 MHz (62.5ns time-base). */ CLK_16M, /** * 2 MHz (0.5us time-base). */ CLK_2M, /** * 250 KHz (4us time-base). */ CLK_250K, /** * 62.5 KHz (16us time-base). */ CLK_62K5 } /** * A sequencer event. Used for tracking execution progress. */ public class Event { /** * Event type. */ public enum Type { /** * The sequencer has been stopped or never started. This will always be accompanied by a * numCuesStarted of 0. This event will also be the first event appearing on the event * queue to designate the the sequencer has been opened and the cue FIFO is at its full * capacity for pushing messages. This is useful if the client wants to pre-fill the * FIFO in order to avoid stalls. */ STOPPED, /** * A new cue has started executing. */ CUE_STARTED, /** * A cue has ended execution and the sequencer is idle as result of a pause request. */ PAUSED, /** * A cue has ended execution and the sequencer is idle as result of the queue becoming * empty. */ STALLED, /** * This event type is only sent once, when the sequencer has been closed. It is mostly * intended to release a client blocking on {@link Sequencer#waitEvent()}. It is also * used if {@link Sequencer#getLastEvent()} is called before any event has been sent. */ CLOSED } /** * The event type. */ public final Type type; /** * This gives a counter of the number cues started execution until now, which is * synchronized with the events. When the first cue begins execution, the event will be * CUE_STARTED and numCuesStarted will be 1. */ public final int numCuesStarted; /** * Constructor. */ public Event(Type t, int n) { type = t; numCuesStarted = n; } } /** * A marker interface for channel configurations. A concrete instance of this describes the * configuration of a single channel. */ public static interface ChannelConfig { } /** * Configuration for a channel of type PWM Position. * <p/> * PWM position channels are channels in which a PWM signal is generated, and the pulse width * controls the position of the actuator. A good example is a hobby servo motor. The main * difference from a PWM speed channel is that the position channel will retain its pulse width * during a stall event. */ public static class ChannelConfigPwmPosition implements ChannelConfig { /** * Specification of the output pin(s) for this channel. */ public final DigitalOutput.Spec[] pinSpec; /** * The clock rate for this channel (cannot be changed on a per-cue basis). */ public final Clock clk; /** * The PWM period, in time-base units, determined by {@link #clk}. Valid values are * [2..65536]. */ public final int period; /** * The initial pulse width (before any cue is executed), in time-base units, determined by * {@link #clk}. Valid values are 0 or [2..65536]. */ public final int initialPulseWidth; /** * Constructor. * <p/> * * @param clk See {@link #clk}. * @param period See {@link #period}. * @param initialPulseWidth See {@link #initialPulseWidth}. * @param pinSpec See {@link #pinSpec}. */ public ChannelConfigPwmPosition(Clock clk, int period, int initialPulseWidth, DigitalOutput.Spec... pinSpec) { if (period < 2 || period > (1 << 16)) { throw new IllegalArgumentException("Period width must be between [2..65536]"); } if (initialPulseWidth != 0 && (initialPulseWidth < 2 || initialPulseWidth > (1 << 16))) { throw new IllegalArgumentException( "Initial pulse width must be 0 or between [2..65536]"); } this.pinSpec = pinSpec; this.clk = clk; this.period = period; this.initialPulseWidth = initialPulseWidth; } } /** * Configuration for a channel of type PWM speed. * <p/> * PWM speed channels are channels in which a PWM signal is generated, and the pulse width * controls the speed of the actuator. A good example is a DC motor. The main difference from a * PWM position channel is that the position channel will go back to its initial pulse width * during a stall event. */ public static class ChannelConfigPwmSpeed implements ChannelConfig { /** * Specification of the output pin(s) for this channel. */ public final DigitalOutput.Spec[] pinSpec; /** * The clock rate for this channel (cannot be changed on a per-cue basis). */ public final Clock clk; /** * The PWM period, in time-base units, determined by {@link #clk}. Valid values are * [2..65536]. */ public final int period; /** * The initial pulse width (before any cue is executed), in time-base units, determined by * {@link #clk}. Valid values are 0 or [2..65536]. Also used in the event of a stall. */ public final int initialPulseWidth; /** * Constructor. * <p/> * * @param clk See {@link #clk}. * @param period See {@link #period}. * @param initialPulseWidth See {@link #initialPulseWidth}. * @param pinSpec See {@link #pinSpec}. */ public ChannelConfigPwmSpeed(Clock clk, int period, int initialPulseWidth, DigitalOutput.Spec... pinSpec) { if (period < 2 || period > (1 << 16)) { throw new IllegalArgumentException("Period width must be between [2..65536]"); } if (initialPulseWidth != 0 && (initialPulseWidth < 2 || initialPulseWidth > (1 << 16))) { throw new IllegalArgumentException( "Initial pulse width must be 0 or between [2..65536]"); } this.pinSpec = pinSpec; this.clk = clk; this.period = period; this.initialPulseWidth = initialPulseWidth; } } /** * Configuration for a channel of type FM speed. * <p/> * FM speed channels are channels in which fixed-width pulses are generated with varying * frequency, which corresponds to the actuator speed. A good example is a stepper motor in an * application which requires speed control and not position control (for the latter see * {@link ChannelConfigSteps}). An FM speed channel will idle (not produce any pulses) during a * stall event. */ public static class ChannelConfigFmSpeed implements ChannelConfig { /** * Specification of the output pin(s) for this channel. */ public final DigitalOutput.Spec[] pinSpec; /** * The clock rate for this channel (cannot be changed on a per-cue basis). */ public final Clock clk; /** * The width (duration) of each pulse, in time-base units, determined by {@link #clk}. Valid * values are [2..65536]. */ public final int pulseWidth; /** * Constructor. * <p/> * * @param clk See {@link #clk}. * @param pulseWidth See {@link #pulseWidth}. * @param pinSpec See {@link #pinSpec}. */ public ChannelConfigFmSpeed(Clock clk, int pulseWidth, DigitalOutput.Spec... pinSpec) { if (pulseWidth < 2 || pulseWidth > (1 << 16)) { throw new IllegalArgumentException("Pulse width must be between [2..65536]"); } this.pinSpec = pinSpec; this.clk = clk; this.pulseWidth = pulseWidth; } } /** * Configuration for a channel of type steps. * <p/> * Steps channels are channels in which fixed-width pulses are generated with varying frequency, * which corresponds to the actuator speed. A good example is a stepper motor in an application * which requires position control. Unlike the FM speed channel, steps channels will generate a * deterministic number of steps in a given duration, as well as allow changing the time-base on * every cue. See {@link ChannelCueSteps} for a discussion on number of steps calculation. A * steps channel will idle (not produce any pulses) during a stall event. */ public static class ChannelConfigSteps implements ChannelConfig { /** * Specification of the output pin(s) for this channel. */ public final DigitalOutput.Spec[] pinSpec; /** * Constructor. * <p/> * * @param pinSpec See {@link #pinSpec}. */ public ChannelConfigSteps(DigitalOutput.Spec... pinSpec) { this.pinSpec = pinSpec; } } /** * Configuration for a binary channel. * <p/> * A binary channel is a simple digital output, which is driven in synchronization with the * sequence. Solenoids, DC motors running at full speed (no PWM) or LED are all examples for * actuators that can be controlled by a binary channel. During a stall event, the channel can * be configured to either retain its last state, or go to its initial state. */ public static class ChannelConfigBinary implements ChannelConfig { /** * Specification of the output pin(s) for this channel. */ public final DigitalOutput.Spec pinSpec; /** * Initial value for this channel (true = HIGH, false = LOW). */ public final boolean initialValue; /** * When true, channel will go to initial state when stalled or stopped. Otherwise, channel * will retain its last state. */ public final boolean initWhenIdle; /** * Constructor. * <p/> * * @param initialValue See {@link #initialValue}. * @param initWhenIdle See {@link #initWhenIdle}. * @param pinSpec See {@link #pinSpec}. */ public ChannelConfigBinary(boolean initialValue, boolean initWhenIdle, DigitalOutput.Spec pinSpec) { this.pinSpec = pinSpec; this.initialValue = initialValue; this.initWhenIdle = initWhenIdle; } } /** * A marker interface for channel cues. A concrete instance of this describes a single cue of a * single channel. */ public static interface ChannelCue { } /** * A cue for a PWM position channel. * <p/> * Determines what is going to be the pulse width will while cue is executing. */ public static class ChannelCuePwmPosition implements ChannelCue { /** * The pulse-width, in time-base units, as determined for this channel in its configuration. * Valid values are 0 or [2..65536]. */ public int pulseWidth; } /** * A cue for a PWM speed channel. * <p/> * Determines what is going to be the pulse width while this cue is executing. */ public static class ChannelCuePwmSpeed implements ChannelCue { /** * The pulse-width, in time-base units, as determined for this channel in its configuration. * Valid values are 0 or [2..65536]. */ public int pulseWidth; } /** * A cue for a FM speed channel. * <p/> * Determines what is going to be the period duration (frequency) while this cue is executing. */ public static class ChannelCueFmSpeed implements ChannelCue { /** * The pulse period, in time-base units, as determined for this channel in its * configuration. Valid values are [0..65536]. Note that: * <ul> * <li>A period of 0 will result in no pulses generated for this cue.</li> * <li>A non-0 period smaller than the pulse duration will result in the output constantly * high.</li> * </ul> */ public int period; } /** * A cue for a steps channel. * <p/> * Determines the clock rate, pulse width and period durations while this cue is executing. This * kind of channel produces deterministic waveforms, which are typically used to generate a * precise number of steps during a given cue period. However, this comes at a cost of being a * little more involved from the user's perspective, since delicate timing considerations need * to be taken into account. * <p/> * The number of steps within a given cue period is given by floor(Tc / Ts), where Tc is the cue * duration and Ts is the step period duration. Each pulse is center-aligned within its period. * In order to maintain a deterministic result, the user must guarantee that no pulse falls * within the last 6 microseconds of the cue period (this effectively limits the maximum pulse * rate to 80[kHz], considering the the pulse itself must be at least 1/8[us] wide, and that the * rising edge of the pulse is center-aligned). Thus, it is possible that due to precision * limitations, in an arbitrarily long period it will be impossible to generate the exact number * of desired pulses. Likewise, a very low pulse rate (high pulse duration) may be outside of * the permitted range or will result in having to use a slower time-base. The solution to both * problems is splitting a single cue into two or more cues of shorted durations, until * eventually the precision is sufficient (this always converges, since eventually we can always * go to arbitrarily short cue durations, so that each one contains either zero or one steps. * <p/> * A steps channel allows determining the clock rate on a per-cue basis. This often allows * avoiding having to split cues, thus resulting in a less total cues and more efficient * execution. The rule for choosing the correct clock is to always use the highest rate that * will cause the resulting period to be <= 2^16. In other words, choose the highest available * clock which is less than or equal to (2^16 / Tp) or (2^16 * Fp), where Tp is the desired * period in seconds, or Fp is the desired frequency in Hz. For example, if we want to generate * pulses at 51Hz, 65536 * Fp = 3.34MHz, so we should use the 2MHz clock, and the period value * will be round(2MHz / 51Hz) = 39216. This result in an actual rate of 2MHz / 39216 ~= * 50.9996[Hz]. */ public static class ChannelCueSteps implements ChannelCue { /** * The clock rate for this cue. See discussion in the class documentation on how to choose * it. */ public Clock clk; /** * The pulse-width, in time-base units, as determined for this channel in its configuration. * Valid values are [0..floor(period / 2)]. */ public int pulseWidth; /** * The pulse period, in time-base units, as determined for this channel in its * configuration. Valid values are [3..65536]. */ public int period; } /** * A cue for a binary channel. * <p/> * This cue determines whether the output should be high or low while the cue is executing. */ public static class ChannelCueBinary implements ChannelCue { /** * The desired output state (true = high, false = low). */ public boolean value; } /** * Push a timed cue to the sequencer. * <p/> * This method will block until there is at least one free space in the FIFO (which may be * forever if the sequencer is not running -- use {@link Sequencer.available()} first in this * case). Then, it will queue the cue for execution. * * @param cues An array of channel cues. Has to be the exact same length as the * {@link ChannelConfig} array that was used to configure the sequencer. Each * element's type should be the counterpart of the corresponding configuration type. * For example, it element number 5 in the configuration array was of type * {@link Sequencer.ChannleConfigBinary}, then cues[5] needs to be of type * {@link Sequencer.ChannelCueBinary} * @param duration The time duration for which this cue is to be executed, before moving to the next * cue (or stalling). The units are 16 microseconds. For example, passing 10 here * would mean a duration of 160 microseconds. Valid values are [2..65536] (approx. * 1.05 seconds). * @throws ConnectionLostException Connection to the IOIO was lost before or during this operation. * @throws InterruptedException The operation was interrupted before completion. */ public void push(ChannelCue[] cues, int duration) throws ConnectionLostException, InterruptedException; /** * Execute a cue until further notice. * <p/> * This method may only be called when the sequencer is not in the Running state. It will not * affect the queue of pending timed-cues previously filled via {@link #push(ChannelCue[], int)} * calls. The cue will be executed until explicitly stopped via {@link #manualStop()}. A * subsequent call to {@link #manualStart(ChannelCue[])} can be used to immediately have a new * cue take into effect. * * @param cues An array of channel cues to execute. See the description of the same argument in * {@link #push(ChannelCue[], int)} for details. * @throws ConnectionLostException Connection to the IOIO was lost before or during this operation. */ public void manualStart(ChannelCue[] cues) throws ConnectionLostException; /** * Stop a manual cue currently running. * <p/> * This may be called only when a the sequencer is not in the Running state, typically in the * Manual state, as result of a previous {@link #manualStart(ChannelCue[])}. This causes the * execution to stop immediately and the sequencer is now back in paused mode, ready for another * manual cue or for resuming execution of its previously queued sequence. Calling while in the * Idle state is legal, but does nothing. * * @throws ConnectionLostException Connection to the IOIO was lost before or during this operation. */ public void manualStop() throws ConnectionLostException; /** * Start execution of the sequence. * <p/> * This method will cause any previously queued cues (via {@link #push(ChannelCue[], int)}) to * start execution in order of pushing, according to their specified timings. The sequencer must * be paused before calling this method. * * @throws ConnectionLostException Connection to the IOIO was lost before or during this operation. */ public void start() throws ConnectionLostException; /** * Pause execution of the sequence. * <p/> * This method can be called when the sequencer is running, as result of previous invocation of * {@link #start()}. It will cause execution to suspend as soon as the currently executing cue * is done. The queue of pending cues will not be affected, and operation can be resumed * seamlessly by calling {@link #start()} again. * * @throws ConnectionLostException Connection to the IOIO was lost before or during this operation. */ public void pause() throws ConnectionLostException; /** * Stop execution of the sequence. * <p/> * This will cause the sequence execution to stop immediately (without waiting for the current * cue to complete). All previously queued cues will be discarded. The sequence will then go to * paused state. * * @throws ConnectionLostException Connection to the IOIO was lost before or during this operation. */ public void stop() throws ConnectionLostException; /** * Get the number of cues which can be pushed without blocking. * <p/> * This is useful for pre-filling the queue before starting the sequencer, or if the client * wants to do other operations on the same thread that pushes cues. The value returned will * indicate how many calls to {@link #push(ChannelCue[], int)} can be completed without * blocking. * * @return The number of available slots in the cue FIFO. */ public int available() throws ConnectionLostException; ; /** * Get the most recent execution event. * <p/> * This includes the event type and the number of cues that started executing, since opening the * sequencer or the last call to {@link #stop()}. Immediately after opening the sequencer, the * event type may be {@link Event.Type.CLOSED}, and as soon as the sequencer finished opening an * {@link Event.Type.STOPPED} will be sent. * * @return The last event. * @throws ConnectionLostException Connection to the IOIO was lost before or during this operation. */ public Event getLastEvent() throws ConnectionLostException; /** * Waits until an execution event occurs and returns it. * <p/> * In case the client is not reading fast enough, older events will be discarded as new once * arrive, so that the queue always stores the most recent events. * * @throws ConnectionLostException Connection to the IOIO was lost before or during this operation. * @throws InterruptedException The operation was interrupted before completion. */ public Event waitEvent() throws ConnectionLostException, InterruptedException; /** * A convenience method for blocking until an event of a certain type appears on the event * queue. All events proceeding this event type, including the event of the requested type will * be removed from the queue and discarded. * * @throws ConnectionLostException Connection to the IOIO was lost before or during this operation. * @throws InterruptedException The operation was interrupted before completion. */ public void waitEventType(Event.Type type) throws ConnectionLostException, InterruptedException; /** * Sets a new size for the incoming event queue. * <p/> * Initially the size of the queue is 32, which should suffice for most purposes. If, however, a * client is not able to read frequently enough to not miss events, increasing the size is an * option. * <p/> * Any pending events will be discarded. It is recommended to call this method only once, * immediately after opening the sequencer. * * @param size The new queue size. * @throws ConnectionLostException Connection to the IOIO was lost before or during this operation. */ public void setEventQueueSize(int size) throws ConnectionLostException; }