Started to update the library to API 3.22 RC

Change-Id: I8eaf3151b1d405799eb582564f0e1e8fbcb7744c
Signed-off-by: Ricky Barrette <rickbarrette@gmail.com>
This commit is contained in:
2012-03-12 00:53:13 -04:00
parent 2b1ee23cff
commit 5f51c1caa1
93 changed files with 4500 additions and 2994 deletions

Binary file not shown.

View File

@@ -52,10 +52,42 @@ import ioio.lib.api.exception.ConnectionLostException;
* Typical usage: * Typical usage:
* *
* <pre> * <pre>
* {@code
* AnalogInput potentiometer = ioio.openAnalogInput(40); * AnalogInput potentiometer = ioio.openAnalogInput(40);
* float value = potentiometer.read(); * float value = potentiometer.read();
* ... * ...
* potentiometer.close(); // pin 40 can now be used for something else. * potentiometer.close(); // pin 40 can now be used for something else.
* }
* </pre>
* <p>
* An alternate usage allows reading periodically sampled data without missing
* samples. The {@link #setBuffer(int)} method must first be called, for setting
* up an internal buffer for queuing samples. Then, samples can be obtained by
* calling {@link #readBuffered()} or {@link #getVoltageBuffered()}. These
* methods will block until a sample is available. If this is undesirable, the
* {@link #available()} method can be called first to check how many samples are
* ready in the buffer. In case the buffer overflows, as result of the client
* not reading fast enough, old samples will be dropped, and the client can
* check {@link #getOverflowCount()} to determine how many samples have been
* lost. The sample rate used for capturing samples can be obtained by calling
* {@link #getSampleRate()}.
* <p>
* The non-buffered versions of the read methods will still behave normally when
* buffering is enabled. The {@link #read()} and {@link #getVoltage()} methods
* will always return the most recent value, regardless of the buffer state.
* <p>
* Typical usage:
*
* <pre>
* AnalogInput potentiometer = ioio.openAnalogInput(40);
* potentiometer.setBuffer(256);
* for (int i = 0; i < 1024; ++i) {
* // next line will block until at least one sample is available
* float sample = potentiometer.readBuffered();
* ...
* }
* ...
* potentiometer.close(); // pin 40 can now be used for something else.
* </pre> * </pre>
* *
* @see IOIO#openAnalogInput(int) * @see IOIO#openAnalogInput(int)
@@ -69,11 +101,13 @@ public interface AnalogInput extends Closeable {
* may block shortly. If this is a problem, the calling thread can be * may block shortly. If this is a problem, the calling thread can be
* interrupted. * interrupted.
* <p> * <p>
* If a scaled value is desired, consider using {@link #read()}. * If a scaled value is desired, consider using {@link #read()}.
* *
* @return The voltage, in Volt units. * @return The voltage, in Volt units.
* @throws InterruptedException The calling thread has been interrupted. * @throws InterruptedException
* @throws ConnectionLostException The connection with the IOIO is lost. * The calling thread has been interrupted.
* @throws ConnectionLostException
* The connection with the IOIO is lost.
* @see #read() * @see #read()
*/ */
public float getVoltage() throws InterruptedException, public float getVoltage() throws InterruptedException,
@@ -81,6 +115,7 @@ public interface AnalogInput extends Closeable {
/** /**
* Gets the maximum value against which {@link #read()} values are scaled. * Gets the maximum value against which {@link #read()} values are scaled.
*
* @return The voltage, in Volts. * @return The voltage, in Volts.
*/ */
public float getReference(); public float getReference();
@@ -96,9 +131,95 @@ public interface AnalogInput extends Closeable {
* If an absolute value is desired, consider using {@link #getVoltage()}. * If an absolute value is desired, consider using {@link #getVoltage()}.
* *
* @return The voltage, in scaled units. * @return The voltage, in scaled units.
* @throws InterruptedException The calling thread has been interrupted. * @throws InterruptedException
* @throws ConnectionLostException The connection with the IOIO is lost. * The calling thread has been interrupted.
* @throws ConnectionLostException
* The connection with the IOIO is lost.
* @see #getVoltage() * @see #getVoltage()
*/ */
public float read() throws InterruptedException, ConnectionLostException; public float read() throws InterruptedException, ConnectionLostException;
/**
* Initializes or destroys an internal buffer, used for queuing sampled
* data. When called with a positive argument, an internal buffer will be
* created, and start storing sampled data. The client can then call
* {@link #readBuffered()} or {@link #getVoltageBuffered()} for obtaining
* buffered samples.
* <p>
* When called with argument of 0, the internal buffer is destroyed.
*
* @param capacity
* The maximum number of unread samples that can be buffered
* before overflow occurs.
* @throws ConnectionLostException
* The connection with the IOIO is lost.
*/
public void setBuffer(int capacity) throws ConnectionLostException;
/**
* Gets the number of samples that have been dropped as result of overflow,
* since {@link #setBuffer(int)} has been called.
*
* @return The number of dropped samples.
* @throws ConnectionLostException
* The connection with the IOIO is lost.
*/
public int getOverflowCount() throws ConnectionLostException;
/**
* Gets the number of samples currently in the buffer. Reading that many
* samples is guaranteed not to block.
*
* @return The number of samples available in the buffer.
* @throws ConnectionLostException
* The connection with the IOIO is lost.
*/
public int available() throws ConnectionLostException;
/**
* Read a sample from the internal buffer. This method will block until at
* least one sample is available, the instance is closed (via
* {@link #close()}), the thread is interrupted (via
* {@link Thread#interrupt()} or connection is lost. {@link #setBuffer(int)}
* must be called prior to this method for setting up an internal buffer for
* storing samples.
*
* @see #getVoltageBuffered()
* @return The earliest (oldest) sample available in the buffer, scaled to
* the range [0,1].
* @throws InterruptedException
* The calling thread has been interrupted.
* @throws ConnectionLostException
* The connection with the IOIO is lost.
*/
public float readBuffered() throws InterruptedException,
ConnectionLostException;
/**
* Read a sample from the internal buffer. This method will block until at
* least one sample is available, the instance is closed (via
* {@link #close()}), the thread is interrupted (via
* {@link Thread#interrupt()} or connection is lost. {@link #setBuffer(int)}
* must be called prior to this method for setting up an internal buffer for
* storing samples.
*
* @see #readBuffered()
* @return The earliest (oldest) sample available in the buffer, in Volt
* units.
* @throws InterruptedException
* The calling thread has been interrupted.
* @throws ConnectionLostException
* The connection with the IOIO is lost.
*/
public float getVoltageBuffered() throws InterruptedException,
ConnectionLostException;
/**
* Gets the sample rate used for obtaining buffered samples.
*
* @return The sample rate, in Hz units.
* @throws ConnectionLostException
* The connection with the IOIO is lost.
*/
public float getSampleRate() throws ConnectionLostException;
} }

View File

@@ -1,140 +1,140 @@
/* /*
* Copyright 2011 Ytai Ben-Tsvi. All rights reserved. * Copyright 2011 Ytai Ben-Tsvi. All rights reserved.
* *
* *
* Redistribution and use in source and binary forms, with or without modification, are * Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met: * permitted provided that the following conditions are met:
* *
* 1. Redistributions of source code must retain the above copyright notice, this list of * 1. Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer. * conditions and the following disclaimer.
* *
* 2. Redistributions in binary form must reproduce the above copyright notice, this list * 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 * of conditions and the following disclaimer in the documentation and/or other materials
* provided with the distribution. * provided with the distribution.
* *
* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND * 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 * 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 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 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 * 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 * 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 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* *
* The views and conclusions contained in the software and documentation are those of the * 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 * authors and should not be interpreted as representing official policies, either expressed
* or implied. * or implied.
*/ */
package ioio.lib.api; package ioio.lib.api;
import ioio.lib.api.exception.ConnectionLostException; import ioio.lib.api.exception.ConnectionLostException;
/** /**
* A pin used for digital input. * A pin used for digital input.
* <p> * <p>
* A digital input pin can be used to read logic-level signals. DigitalInput * A digital input pin can be used to read logic-level signals. DigitalInput
* instances are obtained by calling {@link IOIO#openDigitalInput(Spec)}. * instances are obtained by calling {@link IOIO#openDigitalInput(DigitalInput.Spec)}.
* <p> * <p>
* The value of the pin is obtained by calling {@link #read()}. It is also * The value of the pin is obtained by calling {@link #read()}. It is also
* possible for the client to block until a certain level is sensed, by using * possible for the client to block until a certain level is sensed, by using
* {@link #waitForValue(boolean)}. * {@link #waitForValue(boolean)}.
* <p> * <p>
* The instance is alive since its creation. The first {@link #read()} call * The instance is alive since its creation. The first {@link #read()} call
* block for a few milliseconds until the initial value is updated. If the * block for a few milliseconds until the initial value is updated. If the
* connection with the IOIO drops at any point, the instance transitions to a * connection with the IOIO drops at any point, the instance transitions to a
* disconnected state, in which every attempt to use the pin (except * disconnected state, in which every attempt to use the pin (except
* {@link #close()}) will throw a {@link ConnectionLostException}. Whenever * {@link #close()}) will throw a {@link ConnectionLostException}. Whenever
* {@link #close()} is invoked the instance may no longer be used. Any resources * {@link #close()} is invoked the instance may no longer be used. Any resources
* associated with it are freed and can be reused. * associated with it are freed and can be reused.
* <p> * <p>
* Typical usage: * Typical usage:
* *
* <pre> * <pre>
* DigitalInput button = ioio.openDigitalInput(10); // used an external pull-up * DigitalInput button = ioio.openDigitalInput(10); // used an external pull-up
* button.waitForValue(false); // wait for press * button.waitForValue(false); // wait for press
* ... * ...
* button.close(); // pin 10 can now be used for something else. * button.close(); // pin 10 can now be used for something else.
* </pre> * </pre>
*/ */
public interface DigitalInput extends Closeable { public interface DigitalInput extends Closeable {
/** /**
* A digital input pin specification, used when opening digital inputs. * A digital input pin specification, used when opening digital inputs.
*/ */
static public class Spec { static public class Spec {
/** Input pin mode. */ /** Input pin mode. */
public enum Mode { public enum Mode {
/** /**
* Pin is floating. When the pin is left disconnected the value * Pin is floating. When the pin is left disconnected the value
* sensed is undefined. Use this mode when an external pull-up or * sensed is undefined. Use this mode when an external pull-up or
* pull-down resistor is used or when interfacing push-pull type * pull-down resistor is used or when interfacing push-pull type
* logic circuits. * logic circuits.
*/ */
FLOATING, FLOATING,
/** /**
* Internal pull-up resistor is used. When the pin is left * Internal pull-up resistor is used. When the pin is left
* disconnected, a logical "HIGH" (true) will be sensed. This is * disconnected, a logical "HIGH" (true) will be sensed. This is
* useful for interfacing with open drain circuits or for * useful for interfacing with open drain circuits or for
* interacting with a switch connected between the pin and ground. * interacting with a switch connected between the pin and ground.
*/ */
PULL_UP, PULL_UP,
/** /**
* Internal pull-down resistor is used. When the pin is left * Internal pull-down resistor is used. When the pin is left
* disconnected, a logical "LOW" (false) will be sensed. This is * disconnected, a logical "LOW" (false) will be sensed. This is
* useful for interacting with a switch connected between the pin * useful for interacting with a switch connected between the pin
* and Vdd. * and Vdd.
*/ */
PULL_DOWN PULL_DOWN
} }
/** The pin number, as labeled on the board. */ /** The pin number, as labeled on the board. */
public int pin; public int pin;
/** The pin mode. */ /** The pin mode. */
public Mode mode; public Mode mode;
/** /**
* Constructor. * Constructor.
* *
* @param pin * @param pin
* Pin number, as labeled on the board. * Pin number, as labeled on the board.
* @param mode * @param mode
* Pin mode. * Pin mode.
*/ */
public Spec(int pin, Mode mode) { public Spec(int pin, Mode mode) {
this.pin = pin; this.pin = pin;
this.mode = mode; this.mode = mode;
} }
/** Shorthand for Spec(pin, Mode.FLOATING). */ /** Shorthand for Spec(pin, Mode.FLOATING). */
public Spec(int pin) { public Spec(int pin) {
this(pin, Mode.FLOATING); this(pin, Mode.FLOATING);
} }
} }
/** /**
* Read the value sensed on the pin. May block for a few milliseconds if * Read the value sensed on the pin. May block for a few milliseconds if
* called right after creation of the instance. If this is a problem, the * called right after creation of the instance. If this is a problem, the
* calling thread may be interrupted. * calling thread may be interrupted.
* *
* @return True for logical "HIGH", false for logical "LOW". * @return True for logical "HIGH", false for logical "LOW".
* @throws InterruptedException * @throws InterruptedException
* The calling thread has been interrupted. * The calling thread has been interrupted.
* @throws ConnectionLostException * @throws ConnectionLostException
* The connection with the IOIO has been lost. * The connection with the IOIO has been lost.
*/ */
public boolean read() throws InterruptedException, ConnectionLostException; public boolean read() throws InterruptedException, ConnectionLostException;
/** /**
* Block until a desired logical level is sensed. The calling thread can be * Block until a desired logical level is sensed. The calling thread can be
* interrupted for aborting this operation. * interrupted for aborting this operation.
* *
* @param value * @param value
* The desired logical level. true for "HIGH", false for "LOW". * The desired logical level. true for "HIGH", false for "LOW".
* @throws InterruptedException * @throws InterruptedException
* The calling thread has been interrupted. * The calling thread has been interrupted.
* @throws ConnectionLostException * @throws ConnectionLostException
* The connection with the IOIO has been lost. * The connection with the IOIO has been lost.
*/ */
public void waitForValue(boolean value) throws InterruptedException, public void waitForValue(boolean value) throws InterruptedException,
ConnectionLostException; ConnectionLostException;
} }

View File

@@ -1,120 +1,120 @@
/* /*
* Copyright 2011 Ytai Ben-Tsvi. All rights reserved. * Copyright 2011 Ytai Ben-Tsvi. All rights reserved.
* *
* *
* Redistribution and use in source and binary forms, with or without modification, are * Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met: * permitted provided that the following conditions are met:
* *
* 1. Redistributions of source code must retain the above copyright notice, this list of * 1. Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer. * conditions and the following disclaimer.
* *
* 2. Redistributions in binary form must reproduce the above copyright notice, this list * 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 * of conditions and the following disclaimer in the documentation and/or other materials
* provided with the distribution. * provided with the distribution.
* *
* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND * 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 * 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 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 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 * 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 * 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 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* *
* The views and conclusions contained in the software and documentation are those of the * 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 * authors and should not be interpreted as representing official policies, either expressed
* or implied. * or implied.
*/ */
package ioio.lib.api; package ioio.lib.api;
import ioio.lib.api.exception.ConnectionLostException; import ioio.lib.api.exception.ConnectionLostException;
/** /**
* A pin used for digital output. * A pin used for digital output.
* <p> * <p>
* A digital input pin can be used to generate logic-level signals. * A digital input pin can be used to generate logic-level signals.
* DigitalOutput instances are obtained by calling * DigitalOutput instances are obtained by calling
* {@link IOIO#openDigitalOutput(Spec, boolean)}. * {@link IOIO#openDigitalOutput(DigitalOutput.Spec, boolean)}.
* <p> * <p>
* The value of the pin is set by calling {@link #write(boolean)}. * The value of the pin is set by calling {@link #write(boolean)}.
* <p> * <p>
* The instance is alive since its creation. If the connection with the IOIO * The instance is alive since its creation. If the connection with the IOIO
* drops at any point, the instance transitions to a disconnected state, in * drops at any point, the instance transitions to a disconnected state, in
* which every attempt to use the pin (except {@link #close()}) will throw a * which every attempt to use the pin (except {@link #close()}) will throw a
* {@link ConnectionLostException}. Whenever {@link #close()} is invoked the * {@link ConnectionLostException}. Whenever {@link #close()} is invoked the
* instance may no longer be used. Any resources associated with it are freed * instance may no longer be used. Any resources associated with it are freed
* and can be reused. * and can be reused.
* <p> * <p>
* Typical usage: * Typical usage:
* *
* <pre> * <pre>
* DigitalOutput led = ioio.openDigitalInput(2); // LED anode on pin 2. * DigitalOutput led = ioio.openDigitalInput(2); // LED anode on pin 2.
* led.write(true); // turn LED on. * led.write(true); // turn LED on.
* ... * ...
* led.close(); // pin 2 can now be used for something else. * led.close(); // pin 2 can now be used for something else.
* </pre> * </pre>
*/ */
public interface DigitalOutput extends Closeable { public interface DigitalOutput extends Closeable {
/** /**
* A digital output pin specification, used when opening digital outputs. * A digital output pin specification, used when opening digital outputs.
*/ */
public static class Spec { public static class Spec {
/** Output pin mode. */ /** Output pin mode. */
public enum Mode { public enum Mode {
/** /**
* Pin operates in push-pull mode, i.e. a logical "HIGH" is * Pin operates in push-pull mode, i.e. a logical "HIGH" is
* represented by a voltage of Vdd on the pin and a logical "LOW" by * represented by a voltage of Vdd on the pin and a logical "LOW" by
* a voltage of 0 (ground). * a voltage of 0 (ground).
*/ */
NORMAL, NORMAL,
/** /**
* Pin operates in open-drain mode, i.e. a logical "HIGH" is * Pin operates in open-drain mode, i.e. a logical "HIGH" is
* represented by a high impedance on the pin (as if it is * represented by a high impedance on the pin (as if it is
* disconnected) and a logical "LOW" by a voltage of 0 (ground). * disconnected) and a logical "LOW" by a voltage of 0 (ground).
* This mode is most commonly used for generating 5V logical signal * This mode is most commonly used for generating 5V logical signal
* on a 3.3V pin: 5V tolerant pins must be used; a pull-up resistor * on a 3.3V pin: 5V tolerant pins must be used; a pull-up resistor
* is connected between the pin and 5V, and the pin is used in open- * is connected between the pin and 5V, and the pin is used in open-
* drain mode. * drain mode.
*/ */
OPEN_DRAIN, OPEN_DRAIN,
} }
/** The pin number, as labeled on the board. */ /** The pin number, as labeled on the board. */
public int pin; public int pin;
/** The pin mode. */ /** The pin mode. */
public Mode mode; public Mode mode;
/** /**
* Constructor. * Constructor.
* *
* @param pin * @param pin
* Pin number, as labeled on the board. * Pin number, as labeled on the board.
* @param mode * @param mode
* Pin mode. * Pin mode.
*/ */
public Spec(int pin, Mode mode) { public Spec(int pin, Mode mode) {
this.pin = pin; this.pin = pin;
this.mode = mode; this.mode = mode;
} }
/** /**
* Shorthand for Spec(pin, Mode.NORMAL). * Shorthand for Spec(pin, Mode.NORMAL).
* *
* @see #Spec(int, Mode) * @see DigitalOutput.Spec#Spec(int, DigitalOutput.Spec.Mode)
*/ */
public Spec(int pin) { public Spec(int pin) {
this(pin, Mode.NORMAL); this(pin, Mode.NORMAL);
} }
} }
/** /**
* Set the output of the pin. * Set the output of the pin.
* *
* @param val * @param val
* The output. true is logical "HIGH", false is logical "LOW". * The output. true is logical "HIGH", false is logical "LOW".
* @throws ConnectionLostException * @throws ConnectionLostException
* The connection with the IOIO has been lost. * The connection with the IOIO has been lost.
*/ */
public void write(boolean val) throws ConnectionLostException; public void write(boolean val) throws ConnectionLostException;
} }

File diff suppressed because it is too large Load Diff

0
IOIOLib/src/ioio/lib/api/IOIOConnection.java Executable file → Normal file
View File

View File

@@ -28,10 +28,14 @@
*/ */
package ioio.lib.api; package ioio.lib.api;
import java.lang.reflect.Constructor;
import ioio.lib.impl.IOIOImpl; import ioio.lib.impl.IOIOImpl;
import ioio.lib.impl.SocketIOIOConnection; import ioio.lib.spi.IOIOConnectionFactory;
import ioio.lib.util.IOIOConnectionRegistry;
import java.util.Collection;
import java.util.NoSuchElementException;
import android.util.Log;
/** /**
* Factory class for creating instances of the IOIO interface. * Factory class for creating instances of the IOIO interface.
@@ -55,22 +59,21 @@ import ioio.lib.impl.SocketIOIOConnection;
* </pre> * </pre>
*/ */
public class IOIOFactory { public class IOIOFactory {
/** The TCP port used for communicating with the IOIO board. */
public static final int IOIO_PORT = 4545;
/** /**
* Create a IOIO instance. This specific implementation creates a IOIO * Create a IOIO instance. This specific implementation creates a IOIO
* instance which works with the actual IOIO board connected via a TCP * instance which works with the actual IOIO board connected via a TCP
* connection (typically over a wired USB connection). * connection (typically over a wired USB connection).
* *
* @return The IOIO instance. * @return The IOIO instance.
*/ */
public static IOIO create() { public static IOIO create() {
Collection<IOIOConnectionFactory> factories = IOIOConnectionRegistry
.getConnectionFactories();
try { try {
return create(SocketIOIOConnection.class.getName(), IOIO_PORT); return create(factories.iterator().next().createConnection());
} catch (ClassNotFoundException e) { } catch (NoSuchElementException e) {
// we shouldn't get here - this class must always exist. Log.e(TAG, "No connection is available. This shouldn't happen.");
throw new RuntimeException("Something is very wrong here"); throw e;
} }
} }
@@ -78,44 +81,15 @@ public class IOIOFactory {
* Create a IOIO instance with a user-provided underlying connection class. * Create a IOIO instance with a user-provided underlying connection class.
* This method should be used for establishing a non-standard connection to * This method should be used for establishing a non-standard connection to
* the IOIO board. * the IOIO board.
* *
* @param connectionClassName * @param connection
* The name of the connection class. Must have a public default * An instance of a IOIO connection.
* constructor. *
*
* @return The IOIO instance. * @return The IOIO instance.
* @throws ClassNotFoundException The given class name was not found.
*/ */
public static IOIO create(String connectionClassName, Object... args) throws ClassNotFoundException {
IOIOConnection connection = createConnectionDynamically(connectionClassName, args);
return create(connection);
}
public static IOIO create(IOIOConnection connection) { public static IOIO create(IOIOConnection connection) {
return new IOIOImpl(connection); return new IOIOImpl(connection);
} }
public static IOIOConnection createConnectionDynamically( private static final String TAG = "IOIOFactory";
String connectionClassName, Object... args)
throws ClassNotFoundException {
Class<?> cls;
cls = Class.forName(connectionClassName);
Object instance;
try {
Class<?>[] argTypes = new Class<?>[args.length];
for (int i = 0; i < args.length; ++i) {
argTypes[i] = args[i].getClass();
}
Constructor<?> constructor = cls.getConstructor(argTypes);
instance = constructor.newInstance(args);
} catch (Exception e) {
throw new IllegalArgumentException(
"Provided class does not have a public ctor with the right signature", e);
}
if (!(instance instanceof IOIOConnection)) {
throw new IllegalArgumentException(
"Provided class does not implement IOIOConnection");
}
return (IOIOConnection) instance;
}
} }

0
IOIOLib/src/ioio/lib/api/IcspMaster.java Executable file → Normal file
View File

2
IOIOLib/src/ioio/lib/api/PulseInput.java Executable file → Normal file
View File

@@ -46,7 +46,7 @@ import ioio.lib.api.exception.ConnectionLostException;
* for measuring a turning shaft's speed. * for measuring a turning shaft's speed.
* <p> * <p>
* {@link PulseInput} instances are obtained by calling * {@link PulseInput} instances are obtained by calling
* {@link IOIO#openPulseInput(ioio.lib.api.DigitalInput.Spec, ClockRate, PulseMode, boolean)} * {@link IOIO#openPulseInput(ioio.lib.api.DigitalInput.Spec, ioio.lib.api.PulseInput.ClockRate, ioio.lib.api.PulseInput.PulseMode, boolean)}
* . When created, some important configuration decisions have to be made: the * . When created, some important configuration decisions have to be made: the
* precision (single or double), the clock rate and the mode of operation. Modes * precision (single or double), the clock rate and the mode of operation. Modes
* are straightforward: {@link PulseMode#POSITIVE} is used for measuring a * are straightforward: {@link PulseMode#POSITIVE} is used for measuring a

13
IOIOLib/src/ioio/lib/api/SpiMaster.java Executable file → Normal file
View File

@@ -28,7 +28,6 @@
*/ */
package ioio.lib.api; package ioio.lib.api;
import ioio.lib.api.DigitalInput.Spec;
import ioio.lib.api.exception.ConnectionLostException; import ioio.lib.api.exception.ConnectionLostException;
/** /**
@@ -41,7 +40,7 @@ import ioio.lib.api.exception.ConnectionLostException;
* between this slave and a respective pin on the master. The MISO line should * between this slave and a respective pin on the master. The MISO line should
* operate in pull-up mode, using either the internal pull-up or an external * operate in pull-up mode, using either the internal pull-up or an external
* resistor. SpiMaster instances are obtained by calling * resistor. SpiMaster instances are obtained by calling
* {@link IOIO#openSpiMaster(Spec, ioio.lib.api.DigitalOutput.Spec, ioio.lib.api.DigitalOutput.Spec, ioio.lib.api.DigitalOutput.Spec[], Config)}. * {@link IOIO#openSpiMaster(DigitalInput.Spec, DigitalOutput.Spec, DigitalOutput.Spec, DigitalOutput.Spec[], SpiMaster.Config)}.
* <p> * <p>
* The SPI protocol is comprised of simultaneous sending and receiving of data * The SPI protocol is comprised of simultaneous sending and receiving of data
* between the bus master and a single slave. By the very nature of this * between the bus master and a single slave. By the very nature of this
@@ -90,9 +89,11 @@ import ioio.lib.api.exception.ConnectionLostException;
* spi.writeRead(request, 2, 4, response, 3); * spi.writeRead(request, 2, 4, response, 3);
* ... * ...
* spi.close(); // free SPI module and pins * spi.close(); // free SPI module and pins
* }</pre> * }
* </pre>
* *
* @see IOIO#openSpiMaster(Spec, ioio.lib.api.DigitalOutput.Spec, ioio.lib.api.DigitalOutput.Spec, ioio.lib.api.DigitalOutput.Spec[], Config) * @see IOIO#openSpiMaster(DigitalInput.Spec, DigitalOutput.Spec,
* DigitalOutput.Spec, DigitalOutput.Spec[], SpiMaster.Config)
*/ */
public interface SpiMaster extends Closeable { public interface SpiMaster extends Closeable {
/** Possible data rates for SPI, in Hz. */ /** Possible data rates for SPI, in Hz. */
@@ -148,7 +149,7 @@ public interface SpiMaster extends Closeable {
* Constructor with common defaults. Equivalent to Config(rate, false, * Constructor with common defaults. Equivalent to Config(rate, false,
* false) * false)
* *
* @see #Config(Rate, boolean, boolean) * @see SpiMaster.Config#Config(SpiMaster.Config.Rate, boolean, boolean)
*/ */
public Config(Rate rate) { public Config(Rate rate) {
this(rate, false, false); this(rate, false, false);
@@ -165,7 +166,7 @@ public interface SpiMaster extends Closeable {
* @param slave * @param slave
* The slave index. It is determined by the index of its * The slave index. It is determined by the index of its
* slave-select pin, as per the array passed to * slave-select pin, as per the array passed to
* {@link IOIO#openSpiMaster(Spec, ioio.lib.api.DigitalOutput.Spec, ioio.lib.api.DigitalOutput.Spec, ioio.lib.api.DigitalOutput.Spec[], Config)} * {@link IOIO#openSpiMaster(DigitalInput.Spec, DigitalOutput.Spec, DigitalOutput.Spec, DigitalOutput.Spec[], SpiMaster.Config)}
* . * .
* @param writeData * @param writeData
* A byte array of data to write. May be null if writeSize is 0. * A byte array of data to write. May be null if writeSize is 0.

4
IOIOLib/src/ioio/lib/api/TwiMaster.java Executable file → Normal file
View File

@@ -39,7 +39,7 @@ import ioio.lib.api.exception.ConnectionLostException;
* requires a physical connection of two lines (SDA, SCL) shared by all the bus * requires a physical connection of two lines (SDA, SCL) shared by all the bus
* nodes, where the SDA is open-drain and externally pulled-up. TwiMaster * nodes, where the SDA is open-drain and externally pulled-up. TwiMaster
* instances are obtained by calling * instances are obtained by calling
* {@link IOIO#openTwiMaster(int, Rate, boolean)}. * {@link IOIO#openTwiMaster(int, ioio.lib.api.TwiMaster.Rate, boolean)}.
* <p> * <p>
* TWI is the generic name for the specific I2C and SMBus protocols, differing * TWI is the generic name for the specific I2C and SMBus protocols, differing
* mostly by the voltage levels they require. This module supports both. * mostly by the voltage levels they require. This module supports both.
@@ -79,7 +79,7 @@ import ioio.lib.api.exception.ConnectionLostException;
* twi.close(); // free TWI module and pins * twi.close(); // free TWI module and pins
* }</pre> * }</pre>
* *
* @see IOIO#openTwiMaster(int, Rate, boolean) * @see IOIO#openTwiMaster(int, ioio.lib.api.TwiMaster.Rate, boolean)
*/ */
public interface TwiMaster extends Closeable { public interface TwiMaster extends Closeable {
enum Rate { enum Rate {

View File

@@ -1,108 +1,107 @@
/* /*
* Copyright 2011 Ytai Ben-Tsvi. All rights reserved. * Copyright 2011 Ytai Ben-Tsvi. All rights reserved.
* *
* *
* Redistribution and use in source and binary forms, with or without modification, are * Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met: * permitted provided that the following conditions are met:
* *
* 1. Redistributions of source code must retain the above copyright notice, this list of * 1. Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer. * conditions and the following disclaimer.
* *
* 2. Redistributions in binary form must reproduce the above copyright notice, this list * 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 * of conditions and the following disclaimer in the documentation and/or other materials
* provided with the distribution. * provided with the distribution.
* *
* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND * 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 * 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 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 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 * 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 * 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 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* *
* The views and conclusions contained in the software and documentation are those of the * 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 * authors and should not be interpreted as representing official policies, either expressed
* or implied. * or implied.
*/ */
package ioio.lib.api; package ioio.lib.api;
import ioio.lib.api.DigitalInput.Spec; import ioio.lib.api.exception.ConnectionLostException;
import ioio.lib.api.exception.ConnectionLostException;
import java.io.InputStream;
import java.io.InputStream; import java.io.OutputStream;
import java.io.OutputStream;
/**
/** * An interface for controlling a UART module.
* An interface for controlling a UART module. * <p>
* <p> * UART is a very common hardware communication protocol, enabling full- duplex,
* UART is a very common hardware communication protocol, enabling full- duplex, * asynchronous point-to-point data transfer. It typically serves for opening
* asynchronous point-to-point data transfer. It typically serves for opening * consoles or as a basis for higher-level protocols, such as MIDI, RS-232 and
* consoles or as a basis for higher-level protocols, such as MIDI, RS-232 and * RS-485. Uart instances are obtained by calling
* RS-485. Uart instances are obtained by calling * {@link IOIO#openUart(DigitalInput.Spec, DigitalOutput.Spec, int, Uart.Parity, Uart.StopBits)}.
* {@link IOIO#openUart(Spec, ioio.lib.api.DigitalOutput.Spec, int, Parity, StopBits)}. * <p>
* <p> * The UART protocol is completely symmetric - there is no "master" and "slave"
* The UART protocol is completely symmetric - there is no "master" and "slave" * at this layer. Each end may send any number of bytes at arbitrary times,
* at this layer. Each end may send any number of bytes at arbitrary times, * making it very useful for terminals and terminal-controllable devices.
* making it very useful for terminals and terminal-controllable devices. * <p>
* <p> * Working with UART is very intuitive - it just provides a standard InputStream
* Working with UART is very intuitive - it just provides a standard InputStream * and/or OutputStream. Optionally, one could create a read-only or write-only
* and/or OutputStream. Optionally, one could create a read-only or write-only * UART instances, by passing null (or INVALID_PIN) for either TX or RX pins.
* UART instances, by passing null (or INVALID_PIN) for either TX or RX pins. * <p>
* <p> * The instance is alive since its creation. If the connection with the IOIO
* The instance is alive since its creation. If the connection with the IOIO * drops at any point, the instance transitions to a disconnected state, which
* drops at any point, the instance transitions to a disconnected state, which * every attempt to use it (except {@link #close()}) will throw a
* every attempt to use it (except {@link #close()}) will throw a * {@link ConnectionLostException}. Whenever {@link #close()} is invoked the
* {@link ConnectionLostException}. Whenever {@link #close()} is invoked the * instance may no longer be used. Any resources associated with it are freed
* instance may no longer be used. Any resources associated with it are freed * and can be reused.
* and can be reused. * <p>
* <p> * Typical usage:
* Typical usage: *
* * <pre>
* <pre> * Uart uart = ioio.openUart(3, 4, 19200, Parity.NONE, StopBits.ONE);
* Uart uart = ioio.openUart(3, 4, 19200, Parity.NONE, StopBits.ONE); * InputStream in = uart.getInputStream();
* InputStream in = uart.getInputStream(); * OutputStream out = uart.getOutputStream();
* OutputStream out = uart.getOutputStream(); * out.write(new String("Hello").getBytes());
* out.write(new String("Hello").getBytes()); * int i = in.read(); // blocking
* int i = in.read(); // blocking * ...
* ... * uart.close(); // free UART module and pins
* uart.close(); // free UART module and pins * </pre>
* </pre> *
* * @see IOIO#openUart(DigitalInput.Spec, DigitalOutput.Spec, int, Uart.Parity,
* @see IOIO#openUart(Spec, ioio.lib.api.DigitalOutput.Spec, int, Parity, * Uart.StopBits)
* StopBits) */
*/ public interface Uart extends Closeable {
public interface Uart extends Closeable { /** Parity-bit mode. */
/** Parity-bit mode. */ enum Parity {
enum Parity { /** No parity. */
/** No parity. */ NONE,
NONE, /** Even parity. */
/** Even parity. */ EVEN,
EVEN, /** Odd parity. */
/** Odd parity. */ ODD
ODD }
}
/** Number of stop-bits. */
/** Number of stop-bits. */ enum StopBits {
enum StopBits { /** One stop bit. */
/** One stop bit. */ ONE,
ONE, /** Two stop bits. */
/** Two stop bits. */ TWO
TWO }
}
/**
/** * Gets the input stream.
* Gets the input stream. *
* * @return An input stream.
* @return An input stream. */
*/ public InputStream getInputStream();
public InputStream getInputStream();
/**
/** * Gets the output stream.
* Gets the output stream. *
* * @return An output stream.
* @return An output stream. */
*/ public OutputStream getOutputStream();
public OutputStream getOutputStream(); }
}

View File

View File

@@ -1,3 +1,32 @@
/*
* Copyright 2011 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.bluetooth; package ioio.lib.bluetooth;
import ioio.lib.api.IOIOConnection; import ioio.lib.api.IOIOConnection;
@@ -8,43 +37,41 @@ import java.io.InputStream;
import java.io.OutputStream; import java.io.OutputStream;
import java.util.UUID; import java.util.UUID;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice; import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothSocket; import android.bluetooth.BluetoothSocket;
import android.os.Build;
import android.util.Log; import android.util.Log;
public class BluetoothIOIOConnection implements IOIOConnection { public class BluetoothIOIOConnection implements IOIOConnection {
private static final String TAG = "BluetoothIOIOConnection"; private static final String TAG = "BluetoothIOIOConnection";
private BluetoothSocket socket_ = null; private BluetoothSocket socket_ = null;
private boolean disconnect_ = false; private boolean disconnect_ = false;
private final BluetoothDevice device_;
private final String name_; private final String name_;
private final String address_; private final String address_;
public BluetoothIOIOConnection(String name, String address) { public BluetoothIOIOConnection(BluetoothDevice device) {
name_ = name; device_ = device;
address_ = address; name_ = device.getName();
address_ = device.getAddress();
} }
@Override @Override
public void waitForConnect() throws ConnectionLostException { public void waitForConnect() throws ConnectionLostException {
final BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
final BluetoothDevice ioioDevice = adapter.getRemoteDevice(address_);
synchronized (this) { synchronized (this) {
if (disconnect_) { if (disconnect_) {
throw new ConnectionLostException(); throw new ConnectionLostException();
} }
Log.v(TAG, name_ + " Creating socket");
try { try {
socket_ = createSocket(ioioDevice); socket_ = createSocket(device_);
} catch (IOException e) { } catch (IOException e) {
throw new ConnectionLostException(e); throw new ConnectionLostException(e);
} }
Log.v(TAG, name_ + " Created socket");
} }
// keep trying to connect as long as we're not aborting // keep trying to connect as long as we're not aborting
while (true) { while (true) {
try { try {
Log.v(TAG, name_ + "Connecting"); Log.v(TAG, "Attempting to connect to Bluetooth device: " + name_);
socket_.connect(); socket_.connect();
Log.v(TAG, "Established connection to device " + name_ Log.v(TAG, "Established connection to device " + name_
+ " address: " + address_); + " address: " + address_);
@@ -61,17 +88,15 @@ public class BluetoothIOIOConnection implements IOIOConnection {
} }
} }
public BluetoothSocket createSocket(final BluetoothDevice device) public static BluetoothSocket createSocket(final BluetoothDevice device)
throws IOException { throws IOException {
try { if (Build.VERSION.SDK_INT >= 10 ) {
// We're trying to create an insecure socket, which is // We're trying to create an insecure socket, which is only
// only supported // supported in API 10 and up. Otherwise, we try a secure socket
// in API 10 and up. If we fail, we try a secure socket // which is in API 7 and up.
// with is in API
// 7 and up.
return device.createInsecureRfcommSocketToServiceRecord(UUID return device.createInsecureRfcommSocketToServiceRecord(UUID
.fromString("00001101-0000-1000-8000-00805F9B34FB")); .fromString("00001101-0000-1000-8000-00805F9B34FB"));
} catch (NoSuchMethodError e) { } else {
return device.createRfcommSocketToServiceRecord(UUID return device.createRfcommSocketToServiceRecord(UUID
.fromString("00001101-0000-1000-8000-00805F9B34FB")); .fromString("00001101-0000-1000-8000-00805F9B34FB"));
} }
@@ -82,7 +107,7 @@ public class BluetoothIOIOConnection implements IOIOConnection {
if (disconnect_) { if (disconnect_) {
return; return;
} }
Log.d(TAG, "Client initiated disconnect"); Log.v(TAG, "Client initiated disconnect");
disconnect_ = true; disconnect_ = true;
if (socket_ != null) { if (socket_ != null) {
try { try {

View File

@@ -0,0 +1,93 @@
/*
* Copyright 2011 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.bluetooth;
import ioio.lib.api.IOIOConnection;
import ioio.lib.spi.IOIOConnectionBootstrap;
import ioio.lib.spi.IOIOConnectionFactory;
import ioio.lib.spi.NoRuntimeSupportException;
import java.util.Collection;
import java.util.Set;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.util.Log;
public class BluetoothIOIOConnectionBootstrap implements
IOIOConnectionBootstrap {
private static final String TAG = "BluetoothIOIOConnectionDiscovery";
private final BluetoothAdapter adapter_;
public BluetoothIOIOConnectionBootstrap() throws NoRuntimeSupportException {
try {
adapter_ = BluetoothAdapter.getDefaultAdapter();
} catch (NoClassDefFoundError e) {
throw new NoRuntimeSupportException(
"Bluetooth is not supported on this device.");
}
}
@Override
public void getFactories(Collection<IOIOConnectionFactory> result) {
try {
Set<BluetoothDevice> bondedDevices = adapter_.getBondedDevices();
for (final BluetoothDevice device : bondedDevices) {
if (device.getName().startsWith("IOIO")) {
result.add(new IOIOConnectionFactory() {
@Override
public String getType() {
return BluetoothIOIOConnection.class
.getCanonicalName();
}
@Override
public Object getExtra() {
return new Object[] { device.getName(),
device.getAddress() };
}
@Override
public IOIOConnection createConnection() {
return new BluetoothIOIOConnection(device);
}
});
}
}
} catch (SecurityException e) {
Log.e(TAG,
"Did you forget to declare uses-permission of android.permission.BLUETOOTH?");
throw e;
} catch (NoClassDefFoundError e) {
Log.w(TAG, "Bluetooth is not supported on this device.", e);
}
}
}

View File

@@ -1,37 +0,0 @@
package ioio.lib.bluetooth;
import ioio.lib.util.IOIOConnectionDiscovery;
import java.util.Collection;
import java.util.Set;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.util.Log;
public class BluetoothIOIOConnectionDiscovery implements
IOIOConnectionDiscovery {
private static final String TAG = "BluetoothIOIOConnectionDiscovery";
@Override
public void getSpecs(Collection<IOIOConnectionSpec> result) {
try {
final BluetoothAdapter adapter = BluetoothAdapter
.getDefaultAdapter();
Set<BluetoothDevice> bondedDevices = adapter.getBondedDevices();
for (BluetoothDevice device : bondedDevices) {
if (device.getName().startsWith("IOIO")) {
result.add(new IOIOConnectionSpec(
BluetoothIOIOConnection.class.getName(),
new Object[] { device.getName(),
device.getAddress() }));
}
}
} catch (SecurityException e) {
Log.e(TAG,
"Did you forget to declare uses-permission of android.permission.BLUETOOTH?");
throw e;
}
}
}

3
IOIOLib/src/ioio/lib/impl/AbstractPin.java Executable file → Normal file
View File

@@ -30,7 +30,7 @@ package ioio.lib.impl;
import ioio.lib.api.exception.ConnectionLostException; import ioio.lib.api.exception.ConnectionLostException;
public abstract class AbstractPin extends AbstractResource { abstract class AbstractPin extends AbstractResource {
protected final int pinNum_; protected final int pinNum_;
AbstractPin(IOIOImpl ioio, int pinNum) throws ConnectionLostException { AbstractPin(IOIOImpl ioio, int pinNum) throws ConnectionLostException {
@@ -38,6 +38,7 @@ public abstract class AbstractPin extends AbstractResource {
pinNum_ = pinNum; pinNum_ = pinNum;
} }
@Override
synchronized public void close() { synchronized public void close() {
super.close(); super.close();
ioio_.closePin(pinNum_); ioio_.closePin(pinNum_);

3
IOIOLib/src/ioio/lib/impl/AbstractResource.java Executable file → Normal file
View File

@@ -32,7 +32,7 @@ import ioio.lib.api.exception.ConnectionLostException;
import ioio.lib.impl.IncomingState.DisconnectListener; import ioio.lib.impl.IncomingState.DisconnectListener;
import ioio.lib.api.Closeable; import ioio.lib.api.Closeable;
public class AbstractResource implements Closeable, DisconnectListener { class AbstractResource implements Closeable, DisconnectListener {
enum State { enum State {
OPEN, OPEN,
CLOSED, CLOSED,
@@ -53,6 +53,7 @@ public class AbstractResource implements Closeable, DisconnectListener {
} }
} }
@Override
synchronized public void close() { synchronized public void close() {
if (state_ == State.CLOSED) { if (state_ == State.CLOSED) {
throw new IllegalStateException("Trying to use a closed resouce"); throw new IllegalStateException("Trying to use a closed resouce");

109
IOIOLib/src/ioio/lib/impl/AnalogInputImpl.java Executable file → Normal file
View File

@@ -28,22 +28,31 @@
*/ */
package ioio.lib.impl; package ioio.lib.impl;
import java.io.IOException;
import ioio.lib.api.AnalogInput; import ioio.lib.api.AnalogInput;
import ioio.lib.api.exception.ConnectionLostException; import ioio.lib.api.exception.ConnectionLostException;
import ioio.lib.impl.IncomingState.InputPinListener; import ioio.lib.impl.IncomingState.InputPinListener;
public class AnalogInputImpl extends AbstractPin implements AnalogInput, InputPinListener { import java.io.IOException;
class AnalogInputImpl extends AbstractPin implements AnalogInput,
InputPinListener {
private int value_; private int value_;
private boolean valid_ = false; private boolean valid_ = false;
short[] buffer_;
int bufferSize_;
int bufferCapacity_;
int bufferReadCursor_;
int bufferWriteCursor_;
int bufferOverflowCount_ = 0;
AnalogInputImpl(IOIOImpl ioio, int pin) throws ConnectionLostException { AnalogInputImpl(IOIOImpl ioio, int pin) throws ConnectionLostException {
super(ioio, pin); super(ioio, pin);
} }
@Override @Override
public float getVoltage() throws InterruptedException, ConnectionLostException { public float getVoltage() throws InterruptedException,
ConnectionLostException {
return read() * getReference(); return read() * getReference();
} }
@@ -55,18 +64,20 @@ public class AnalogInputImpl extends AbstractPin implements AnalogInput, InputPi
@Override @Override
synchronized public void setValue(int value) { synchronized public void setValue(int value) {
// Log.v("AnalogInputImpl", "Pin " + pinNum_ + " value is " + value); // Log.v("AnalogInputImpl", "Pin " + pinNum_ + " value is " + value);
assert(value >= 0 || value < 1024); assert (value >= 0 && value < 1024);
value_ = value; value_ = value;
if (!valid_) { if (!valid_) {
valid_ = true; valid_ = true;
notifyAll(); notifyAll();
} }
bufferPush((short) value);
} }
@Override @Override
synchronized public float read() throws InterruptedException, ConnectionLostException { synchronized public float read() throws InterruptedException,
ConnectionLostException {
checkState(); checkState();
while (!valid_ && state_ != State.DISCONNECTED) { while (!valid_ && state_ == State.OPEN) {
wait(); wait();
} }
checkState(); checkState();
@@ -87,4 +98,82 @@ public class AnalogInputImpl extends AbstractPin implements AnalogInput, InputPi
} catch (IOException e) { } catch (IOException e) {
} }
} }
@Override
public synchronized void setBuffer(int capacity)
throws ConnectionLostException {
checkState();
if (capacity <= 0) {
buffer_ = null;
} else {
buffer_ = new short[capacity];
}
bufferCapacity_ = capacity;
bufferSize_ = 0;
bufferReadCursor_ = 0;
bufferWriteCursor_ = 0;
bufferOverflowCount_ = 0;
}
@Override
public float readBuffered() throws InterruptedException,
ConnectionLostException {
checkState();
return (float) bufferPull() / 1023.0f;
}
@Override
public float getVoltageBuffered() throws InterruptedException,
ConnectionLostException {
return readBuffered() * getReference();
}
private void bufferPush(short value) {
if (buffer_ == null) {
return;
}
if (bufferSize_ == bufferCapacity_) {
++bufferOverflowCount_;
} else {
++bufferSize_;
}
buffer_[bufferWriteCursor_++] = value;
if (bufferWriteCursor_ == bufferCapacity_) {
bufferWriteCursor_ = 0;
}
notifyAll();
}
private synchronized short bufferPull() throws InterruptedException,
ConnectionLostException {
if (buffer_ == null) {
throw new IllegalStateException(
"Need to call setBuffer() before reading buffered values.");
}
while (bufferSize_ == 0 && state_ == State.OPEN) {
wait();
}
checkState();
short result = buffer_[bufferReadCursor_++];
if (bufferReadCursor_ == bufferCapacity_) {
bufferReadCursor_ = 0;
}
--bufferSize_;
return result;
}
@Override
public int getOverflowCount() throws ConnectionLostException {
return bufferOverflowCount_;
}
@Override
public float getSampleRate() throws ConnectionLostException {
return 1000.0f;
}
@Override
public int available() throws ConnectionLostException {
return bufferSize_;
}
} }

90
IOIOLib/src/ioio/lib/impl/Constants.java Executable file → Normal file
View File

@@ -1,45 +1,45 @@
/* /*
* Copyright 2011 Ytai Ben-Tsvi. All rights reserved. * Copyright 2011 Ytai Ben-Tsvi. All rights reserved.
* *
* *
* Redistribution and use in source and binary forms, with or without modification, are * Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met: * permitted provided that the following conditions are met:
* *
* 1. Redistributions of source code must retain the above copyright notice, this list of * 1. Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer. * conditions and the following disclaimer.
* *
* 2. Redistributions in binary form must reproduce the above copyright notice, this list * 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 * of conditions and the following disclaimer in the documentation and/or other materials
* provided with the distribution. * provided with the distribution.
* *
* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND * 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 * 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 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 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 * 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 * 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 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* *
* The views and conclusions contained in the software and documentation are those of the * 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 * authors and should not be interpreted as representing official policies, either expressed
* or implied. * or implied.
*/ */
package ioio.lib.impl; package ioio.lib.impl;
class Constants { class Constants {
static final int NUM_PINS = 49; static final int NUM_PINS = 49;
static final int NUM_ANALOG_PINS = 16; static final int NUM_ANALOG_PINS = 16;
static final int NUM_PWM_MODULES = 9; static final int NUM_PWM_MODULES = 9;
static final int NUM_UART_MODULES = 4; static final int NUM_UART_MODULES = 4;
static final int NUM_SPI_MODULES = 3; static final int NUM_SPI_MODULES = 3;
static final int NUM_TWI_MODULES = 3; static final int NUM_TWI_MODULES = 3;
static final int[] INCAP_MODULES_DOUBLE = new int[] { 0, 2, 4}; static final int[] INCAP_MODULES_DOUBLE = new int[] { 0, 2, 4};
static final int[] INCAP_MODULES_SINGLE = new int[] { 6, 7, 8}; static final int[] INCAP_MODULES_SINGLE = new int[] { 6, 7, 8};
static final int BUFFER_SIZE = 1024; static final int BUFFER_SIZE = 1024;
static final int PACKET_BUFFER_SIZE = 256; static final int PACKET_BUFFER_SIZE = 256;
static final int[][] TWI_PINS = new int[][] {{ 4, 5 }, { 47, 48 }, { 26, 25 }}; static final int[][] TWI_PINS = new int[][] {{ 4, 5 }, { 47, 48 }, { 26, 25 }};
static final int[] ICSP_PINS = new int[] { 36, 37, 38 }; static final int[] ICSP_PINS = new int[] { 36, 37, 38 };
} }

3
IOIOLib/src/ioio/lib/impl/DigitalInputImpl.java Executable file → Normal file
View File

@@ -34,7 +34,7 @@ import ioio.lib.impl.IncomingState.InputPinListener;
import java.io.IOException; import java.io.IOException;
public class DigitalInputImpl extends AbstractPin implements DigitalInput, class DigitalInputImpl extends AbstractPin implements DigitalInput,
InputPinListener { InputPinListener {
private boolean value_; private boolean value_;
private boolean valid_ = false; private boolean valid_ = false;
@@ -54,6 +54,7 @@ public class DigitalInputImpl extends AbstractPin implements DigitalInput,
notifyAll(); notifyAll();
} }
@Override
synchronized public void waitForValue(boolean value) synchronized public void waitForValue(boolean value)
throws InterruptedException, ConnectionLostException { throws InterruptedException, ConnectionLostException {
checkState(); checkState();

18
IOIOLib/src/ioio/lib/impl/DigitalOutputImpl.java Executable file → Normal file
View File

@@ -33,18 +33,24 @@ import ioio.lib.api.exception.ConnectionLostException;
import java.io.IOException; import java.io.IOException;
public class DigitalOutputImpl extends AbstractPin implements DigitalOutput { class DigitalOutputImpl extends AbstractPin implements DigitalOutput {
DigitalOutputImpl(IOIOImpl ioio, int pin) throws ConnectionLostException { boolean value_;
DigitalOutputImpl(IOIOImpl ioio, int pin, boolean startValue) throws ConnectionLostException {
super(ioio, pin); super(ioio, pin);
value_ = startValue;
} }
@Override @Override
synchronized public void write(boolean val) throws ConnectionLostException { synchronized public void write(boolean val) throws ConnectionLostException {
checkState(); checkState();
try { if (val != value_) {
ioio_.protocol_.setDigitalOutLevel(pinNum_, val); try {
} catch (IOException e) { ioio_.protocol_.setDigitalOutLevel(pinNum_, val);
throw new ConnectionLostException(e); value_ = val;
} catch (IOException e) {
throw new ConnectionLostException(e);
}
} }
} }
} }

View File

@@ -33,7 +33,7 @@ import java.io.OutputStream;
import java.util.concurrent.ArrayBlockingQueue; import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue; import java.util.concurrent.BlockingQueue;
public class FlowControlledOutputStream extends OutputStream { class FlowControlledOutputStream extends OutputStream {
interface Sender { interface Sender {
void send(byte[] data, int size); void send(byte[] data, int size);
} }
@@ -91,15 +91,14 @@ public class FlowControlledOutputStream extends OutputStream {
@Override @Override
synchronized public void close() { synchronized public void close() {
if (closed_) {
return;
}
closed_ = true; closed_ = true;
notifyAll(); notifyAll();
thread_.interrupt(); thread_.interrupt();
} }
synchronized public void kill() {
thread_.interrupt();
}
class FlushThread extends Thread { class FlushThread extends Thread {
@Override @Override
public void run() { public void run() {

View File

@@ -32,7 +32,7 @@ import java.io.IOException;
import java.util.concurrent.ArrayBlockingQueue; import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue; import java.util.concurrent.BlockingQueue;
public class FlowControlledPacketSender { class FlowControlledPacketSender {
interface Packet { interface Packet {
int getSize(); int getSize();
} }

1354
IOIOLib/src/ioio/lib/impl/IOIOImpl.java Executable file → Normal file

File diff suppressed because it is too large Load Diff

1655
IOIOLib/src/ioio/lib/impl/IOIOProtocol.java Executable file → Normal file

File diff suppressed because it is too large Load Diff

2
IOIOLib/src/ioio/lib/impl/IcspMasterImpl.java Executable file → Normal file
View File

@@ -36,7 +36,7 @@ import java.io.IOException;
import java.util.LinkedList; import java.util.LinkedList;
import java.util.Queue; import java.util.Queue;
public class IcspMasterImpl extends AbstractResource implements IcspMaster, class IcspMasterImpl extends AbstractResource implements IcspMaster,
DataModuleListener { DataModuleListener {
private Queue<Integer> resultQueue_ = new LinkedList<Integer>(); private Queue<Integer> resultQueue_ = new LinkedList<Integer>();
private int rxRemaining_ = 0; private int rxRemaining_ = 0;

2
IOIOLib/src/ioio/lib/impl/IncapImpl.java Executable file → Normal file
View File

@@ -7,7 +7,7 @@ import ioio.lib.impl.IncomingState.DataModuleListener;
import java.util.LinkedList; import java.util.LinkedList;
import java.util.Queue; import java.util.Queue;
public class IncapImpl extends AbstractPin implements DataModuleListener, class IncapImpl extends AbstractPin implements DataModuleListener,
PulseInput { PulseInput {
private static final int MAX_QUEUE_LEN = 32; private static final int MAX_QUEUE_LEN = 32;
private final PulseMode mode_; private final PulseMode mode_;

2
IOIOLib/src/ioio/lib/impl/IncomingState.java Executable file → Normal file
View File

@@ -38,7 +38,7 @@ import java.util.concurrent.ConcurrentLinkedQueue;
import android.util.Log; import android.util.Log;
public class IncomingState implements IncomingHandler { class IncomingState implements IncomingHandler {
enum ConnectionState { enum ConnectionState {
INIT, ESTABLISHED, CONNECTED, DISCONNECTED, UNSUPPORTED_IID INIT, ESTABLISHED, CONNECTED, DISCONNECTED, UNSUPPORTED_IID
} }

2
IOIOLib/src/ioio/lib/impl/ModuleAllocator.java Executable file → Normal file
View File

@@ -44,7 +44,7 @@ import java.util.TreeSet;
* *
* @author birmiwal * @author birmiwal
*/ */
public class ModuleAllocator { class ModuleAllocator {
private final Set<Integer> availableModuleIds_; private final Set<Integer> availableModuleIds_;
private final Set<Integer> allocatedModuleIds_; private final Set<Integer> allocatedModuleIds_;
private final String name_; private final String name_;

2
IOIOLib/src/ioio/lib/impl/PinFunctionMap.java Executable file → Normal file
View File

@@ -29,7 +29,7 @@
package ioio.lib.impl; package ioio.lib.impl;
public class PinFunctionMap { class PinFunctionMap {
private static final boolean[] PERIPHERAL_OUT = new boolean[] { true, private static final boolean[] PERIPHERAL_OUT = new boolean[] { true,
false, false, true, true, true, true, true, false, false, true, false, false, true, true, true, true, true, false, false, true,
true, true, true, true, false, false, false, false, false, false, true, true, true, true, false, false, false, false, false, false,

2
IOIOLib/src/ioio/lib/impl/PwmImpl.java Executable file → Normal file
View File

@@ -33,7 +33,7 @@ import ioio.lib.api.exception.ConnectionLostException;
import java.io.IOException; import java.io.IOException;
public class PwmImpl extends AbstractResource implements PwmOutput { class PwmImpl extends AbstractResource implements PwmOutput {
private final int pwmNum_; private final int pwmNum_;
private final int pinNum_; private final int pinNum_;
private final float baseUs_; private final float baseUs_;

56
IOIOLib/src/ioio/lib/impl/QueueInputStream.java Executable file → Normal file
View File

@@ -35,26 +35,60 @@ import java.util.concurrent.ArrayBlockingQueue;
import android.util.Log; import android.util.Log;
public class QueueInputStream extends InputStream { class QueueInputStream extends InputStream {
private enum State {
OPEN, CLOSED, KILLED
};
private final Queue<Byte> queue_ = new ArrayBlockingQueue<Byte>( private final Queue<Byte> queue_ = new ArrayBlockingQueue<Byte>(
Constants.BUFFER_SIZE); Constants.BUFFER_SIZE);
private boolean closed_ = false; private State state_ = State.OPEN;
@Override @Override
synchronized public int read() throws IOException { synchronized public int read() throws IOException {
try { try {
while (!closed_ && queue_.isEmpty()) { while (state_ == State.OPEN && queue_.isEmpty()) {
wait(); wait();
} }
if (closed_) { if (state_ == State.KILLED) {
throw new IOException("Stream has been closed"); throw new IOException("Stream has been closed");
} }
if (state_ == State.CLOSED && queue_.isEmpty()) {
return -1;
}
return ((int) queue_.remove()) & 0xFF; return ((int) queue_.remove()) & 0xFF;
} catch (InterruptedException e) { } catch (InterruptedException e) {
throw new IOException("Interrupted"); throw new IOException("Interrupted");
} }
} }
@Override
synchronized public int read(byte[] b, int off, int len) throws IOException {
if (len == 0) {
return 0;
}
try {
while (state_ == State.OPEN && queue_.isEmpty()) {
wait();
}
if (state_ == State.KILLED) {
throw new IOException("Stream has been closed");
}
if (state_ == State.CLOSED && queue_.isEmpty()) {
return -1;
}
if (len > queue_.size()) {
len = queue_.size();
}
for (int i = 0; i < len; ++i) {
b[off++] = queue_.remove();
}
return len;
} catch (InterruptedException e) {
throw new IOException("Interrupted");
}
}
synchronized public void write(byte[] data, int size) { synchronized public void write(byte[] data, int size) {
for (int i = 0; i < size; ++i) { for (int i = 0; i < size; ++i) {
if (queue_.size() == Constants.BUFFER_SIZE) { if (queue_.size() == Constants.BUFFER_SIZE) {
@@ -73,7 +107,19 @@ public class QueueInputStream extends InputStream {
@Override @Override
synchronized public void close() { synchronized public void close() {
closed_ = true; if (state_ != State.OPEN) {
return;
}
state_ = State.CLOSED;
notifyAll();
}
synchronized public void kill() {
if (state_ != State.OPEN) {
return;
}
state_ = State.KILLED;
notifyAll();
} }
} }

19
IOIOLib/src/ioio/lib/impl/SocketIOIOConnection.java Executable file → Normal file
View File

@@ -41,6 +41,7 @@ import java.net.SocketException;
import android.util.Log; import android.util.Log;
public class SocketIOIOConnection implements IOIOConnection { public class SocketIOIOConnection implements IOIOConnection {
private static final String TAG = "SocketIOIOConnection";
private final int port_; private final int port_;
private ServerSocket server_ = null; private ServerSocket server_ = null;
private Socket socket_ = null; private Socket socket_ = null;
@@ -48,7 +49,7 @@ public class SocketIOIOConnection implements IOIOConnection {
private boolean server_owned_by_connect_ = true; private boolean server_owned_by_connect_ = true;
private boolean socket_owned_by_connect_ = true; private boolean socket_owned_by_connect_ = true;
public SocketIOIOConnection(Integer port) { public SocketIOIOConnection(int port) {
port_ = port; port_ = port;
} }
@@ -59,13 +60,13 @@ public class SocketIOIOConnection implements IOIOConnection {
if (disconnect_) { if (disconnect_) {
throw new ConnectionLostException(); throw new ConnectionLostException();
} }
Log.d("SocketIOIOConnection", "Creating server socket"); Log.v(TAG, "Creating server socket");
server_ = new ServerSocket(port_); server_ = new ServerSocket(port_);
server_owned_by_connect_ = false; server_owned_by_connect_ = false;
} }
Log.d("SocketIOIOConnection", "Waiting for TCP connection"); Log.v(TAG, "Waiting for TCP connection");
socket_ = server_.accept(); socket_ = server_.accept();
Log.d("SocketIOIOConnection", "TCP connected"); Log.v(TAG, "TCP connected");
synchronized (this) { synchronized (this) {
if (disconnect_) { if (disconnect_) {
socket_.close(); socket_.close();
@@ -80,18 +81,18 @@ public class SocketIOIOConnection implements IOIOConnection {
try { try {
server_.close(); server_.close();
} catch (IOException e1) { } catch (IOException e1) {
Log.e("SocketIOIOConnection", "Unexpected exception", e1); Log.e(TAG, "Unexpected exception", e1);
} }
} }
if (socket_owned_by_connect_ && socket_ != null) { if (socket_owned_by_connect_ && socket_ != null) {
try { try {
socket_.close(); socket_.close();
} catch (IOException e1) { } catch (IOException e1) {
Log.e("SocketIOIOConnection", "Unexpected exception", e1); Log.e(TAG, "Unexpected exception", e1);
} }
} }
if (e instanceof SocketException && e.getMessage().equals("Permission denied")) { if (e instanceof SocketException && e.getMessage().equals("Permission denied")) {
Log.e("SocketIOIOConnection", "Did you forget to declare uses-permission of android.permission.INTERNET?"); Log.e(TAG, "Did you forget to declare uses-permission of android.permission.INTERNET?");
} }
throw new ConnectionLostException(e); throw new ConnectionLostException(e);
} }
@@ -103,13 +104,13 @@ public class SocketIOIOConnection implements IOIOConnection {
if (disconnect_) { if (disconnect_) {
return; return;
} }
Log.d("SocketIOIOConnection", "Client initiated disconnect"); Log.v(TAG, "Client initiated disconnect");
disconnect_ = true; disconnect_ = true;
if (!server_owned_by_connect_) { if (!server_owned_by_connect_) {
try { try {
server_.close(); server_.close();
} catch (IOException e1) { } catch (IOException e1) {
Log.e("SocketIOIOConnection", "Unexpected exception", e1); Log.e(TAG, "Unexpected exception", e1);
} }
} }
if (!socket_owned_by_connect_) { if (!socket_owned_by_connect_) {

View File

@@ -0,0 +1,63 @@
/*
* Copyright 2011 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.impl;
import ioio.lib.api.IOIOConnection;
import ioio.lib.spi.IOIOConnectionBootstrap;
import ioio.lib.spi.IOIOConnectionFactory;
import java.util.Collection;
public class SocketIOIOConnectionBootstrap implements IOIOConnectionBootstrap {
/** The TCP port used for communicating with the IOIO board. */
public static final int IOIO_PORT = 4545;
@Override
public void getFactories(Collection<IOIOConnectionFactory> result) {
result.add(new IOIOConnectionFactory() {
private Integer port_ = new Integer(IOIO_PORT);
@Override
public String getType() {
return SocketIOIOConnection.class.getCanonicalName();
}
@Override
public Object getExtra() {
return port_;
}
@Override
public IOIOConnection createConnection() {
return new SocketIOIOConnection(IOIO_PORT);
}
});
}
}

2
IOIOLib/src/ioio/lib/impl/SpiMasterImpl.java Executable file → Normal file
View File

@@ -42,7 +42,7 @@ import java.util.concurrent.ConcurrentLinkedQueue;
import android.util.Log; import android.util.Log;
public class SpiMasterImpl extends AbstractResource implements SpiMaster, class SpiMasterImpl extends AbstractResource implements SpiMaster,
DataModuleListener, Sender { DataModuleListener, Sender {
public class SpiResult implements Result { public class SpiResult implements Result {
boolean ready_; boolean ready_;

2
IOIOLib/src/ioio/lib/impl/TwiMasterImpl.java Executable file → Normal file
View File

@@ -40,7 +40,7 @@ import java.util.concurrent.ConcurrentLinkedQueue;
import android.util.Log; import android.util.Log;
public class TwiMasterImpl extends AbstractResource implements TwiMaster, class TwiMasterImpl extends AbstractResource implements TwiMaster,
DataModuleListener, Sender { DataModuleListener, Sender {
class TwiResult implements Result { class TwiResult implements Result {
boolean ready_ = false; boolean ready_ = false;

5
IOIOLib/src/ioio/lib/impl/UartImpl.java Executable file → Normal file
View File

@@ -40,7 +40,7 @@ import java.io.OutputStream;
import android.util.Log; import android.util.Log;
public class UartImpl extends AbstractResource implements DataModuleListener, Sender, Uart { class UartImpl extends AbstractResource implements DataModuleListener, Sender, Uart {
private static final int MAX_PACKET = 64; private static final int MAX_PACKET = 64;
private final int uartNum_; private final int uartNum_;
@@ -87,7 +87,8 @@ public class UartImpl extends AbstractResource implements DataModuleListener, Se
@Override @Override
synchronized public void disconnected() { synchronized public void disconnected() {
super.disconnected(); super.disconnected();
outgoing_.kill(); incoming_.kill();
outgoing_.close();
} }
@Override @Override

View File

@@ -0,0 +1,41 @@
/*
* Copyright 2011 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.spi;
import java.util.Collection;
/**
* Implementing class must have a default constructor. The default constructor
* must throw a NoRuntimeSupportException in case the required libraries for
* implementing the connections are not available in run-time.
*/
public interface IOIOConnectionBootstrap {
public void getFactories(Collection<IOIOConnectionFactory> result);
}

View File

@@ -0,0 +1,21 @@
package ioio.lib.spi;
import ioio.lib.api.IOIOConnection;
public interface IOIOConnectionFactory {
/**
* A unique name of the connection type. Typically a fully-qualified
* name of the connection class.
*/
public String getType();
/**
* Extra information on the connection. This is specific to the
* connection type. For example, for a Bluetooth connection, this is an
* array containing the name and the Bluetooth address of the remote
* IOIO.
*/
public Object getExtra();
public IOIOConnection createConnection();
}

View File

@@ -0,0 +1,9 @@
package ioio.lib.spi;
public class NoRuntimeSupportException extends Exception {
private static final long serialVersionUID = -6559208663699429514L;
public NoRuntimeSupportException(String desc) {
super(desc);
}
}

664
IOIOLib/src/ioio/lib/util/AbstractIOIOActivity.java Executable file → Normal file
View File

@@ -1,295 +1,369 @@
package ioio.lib.util; /*
* Copyright 2011 Ytai Ben-Tsvi. All rights reserved.
import ioio.lib.api.IOIO; *
import ioio.lib.api.IOIOFactory; *
import ioio.lib.api.exception.ConnectionLostException; * Redistribution and use in source and binary forms, with or without modification, are
import ioio.lib.api.exception.IncompatibilityException; * permitted provided that the following conditions are met:
import ioio.lib.util.IOIOConnectionDiscovery.IOIOConnectionSpec; *
* 1. Redistributions of source code must retain the above copyright notice, this list of
import java.util.Collection; * conditions and the following disclaimer.
import java.util.LinkedList; *
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
import android.app.Activity; * of conditions and the following disclaimer in the documentation and/or other materials
import android.os.Looper; * provided with the distribution.
import android.util.Log; *
* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
/** * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* A convenience class for easy creation of IOIO-based applications. * 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
* It is used by creating a concrete Activity in your application, which extends * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* this class. This class then takes care of proper creation and abortion of the * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* IOIO connection and of a dedicated thread for IOIO communication. * 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
* In the basic usage the client should extend this class and implement * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* {@link #createIOIOThread()}, which should return an implementation of the *
* {@link IOIOThread} abstract class. In this implementation, the client * The views and conclusions contained in the software and documentation are those of the
* implements the {@link IOIOThread#setup()} method, which gets called as soon * authors and should not be interpreted as representing official policies, either expressed
* as communication with the IOIO is established, and the {@link IOIOThread * or implied.
* #loop()} method, which gets called repetitively as long as the IOIO is */
* connected. Both methods should access the {@link IOIOThread#ioio_} field for
* controlling the IOIO. package ioio.lib.util;
*
* In addition, the {@link IOIOThread#disconnected()} method may be overridden import ioio.lib.api.IOIO;
* in order to execute logic as soon as a disconnection occurs for whichever import ioio.lib.api.IOIOFactory;
* reason. The {@link IOIOThread#incompatible()} method may be overridden in import ioio.lib.api.exception.ConnectionLostException;
* order to take action in case where a IOIO whose firmware is incompatible with import ioio.lib.api.exception.IncompatibilityException;
* the IOIOLib version that application is built with. import ioio.lib.spi.IOIOConnectionBootstrap;
* import ioio.lib.spi.IOIOConnectionFactory;
* In a more advanced use case, more than one IOIO is available. In this case, a import ioio.lib.util.android.ContextWrapperDependent;
* thread will be created for each IOIO, whose semantics are as defined above.
* If the client needs to be able to distinguish between them, it is possible to import java.util.Collection;
* override {@link #createIOIOThread(String, Object[])} instead of import java.util.LinkedList;
* {@link #createIOIOThread()}. The first argument provided will contain the
* connection class name, such as ioio.lib.impl.SocketIOIOConnection for a import android.app.Activity;
* connection established over a TCP socket (which is used over ADB). The second import android.content.Intent;
* argument will contain information specific to the connection type. For import android.os.Bundle;
* example, in the case of SocketIOIOConnection, the array will contain an import android.util.Log;
* {@link Integer} representing the local port number.
* /**
*/ * A convenience class for easy creation of IOIO-based applications.
public abstract class AbstractIOIOActivity extends Activity { *
private static final String TAG = "AbstractIOIOActivity"; * It is used by creating a concrete Activity in your application, which extends
private IOIOConnectionSpec currentSpec_; * this class. This class then takes care of proper creation and abortion of the
private Collection<IOIOThread> threads_ = new LinkedList<IOIOThread>(); * IOIO connection and of a dedicated thread for IOIO communication.
*
/** * In the basic usage the client should extend this class and implement
* Subclasses should call this method from their own onResume() if * {@link #createIOIOThread()}, which should return an implementation of the
* overloaded. It takes care of connecting with the IOIO. * {@link AbstractIOIOActivity.IOIOThread} abstract class. In this
*/ * implementation, the client implements the
@Override * {@link AbstractIOIOActivity.IOIOThread#setup()} method, which gets called as
protected void onResume() { * soon as communication with the IOIO is established, and the
super.onResume(); * {@link AbstractIOIOActivity.IOIOThread#loop()} method, which gets called
createAllThreads(); * repetitively as long as the IOIO is connected. Both methods should access the
startAllThreads(); * {@link AbstractIOIOActivity.IOIOThread#ioio_} field for controlling the IOIO.
} *
* In addition, the {@link AbstractIOIOActivity.IOIOThread#disconnected()}
/** * method may be overridden in order to execute logic as soon as a disconnection
* Subclasses should call this method from their own onPause() if * occurs for whichever reason. The
* overloaded. It takes care of disconnecting from the IOIO. * {@link AbstractIOIOActivity.IOIOThread#incompatible()} method may be
*/ * overridden in order to take action in case where a IOIO whose firmware is
@Override * incompatible with the IOIOLib version that application is built with.
protected void onPause() { *
super.onPause(); * In a more advanced use case, more than one IOIO is available. In this case, a
abortAllThreads(); * thread will be created for each IOIO, whose semantics are as defined above.
try { * If the client needs to be able to distinguish between them, it is possible to
joinAllThreads(); * override {@link #createIOIOThread(String, Object)} instead of
} catch (InterruptedException e) { * {@link #createIOIOThread()}. The first argument provided will contain the
} * connection class name, such as ioio.lib.impl.SocketIOIOConnection for a
} * connection established over a TCP socket (which is used over ADB). The second
* argument will contain information specific to the connection type. For
/** * example, in the case of SocketIOIOConnection, the second argument will
* Subclasses should implement this method by returning a concrete subclass * contain an {@link Integer} representing the local port number.
* of {@link IOIOThread}. <code>null</code> may be returned if the client *
* is not interested to connect a thread for this IOIO. In multi-IOIO * @deprecated Please use {@link ioio.lib.util.android.IOIOActivity} instead.
* scenarios, where you want to identify which IOIO the thread is for, */
* consider using {@link #createIOIOThread()} instead. public abstract class AbstractIOIOActivity extends Activity {
* private static final String TAG = "AbstractIOIOActivity";
* @return An implementation of {@link IOIOThread}, or <code>null</code> to
* skip. static {
*/ IOIOConnectionRegistry
protected IOIOThread createIOIOThread() { .addBootstraps(new String[] {
return null; "ioio.lib.android.accessory.AccessoryConnectionBootstrap",
} "ioio.lib.android.bluetooth.BluetoothIOIOConnectionBootstrap" });
}
/**
* Subclasses should implement this method by returning a concrete subclass private Collection<IOIOThread> threads_ = new LinkedList<IOIOThread>();
* of {@link IOIOThread}. This overload is useful in multi-IOIO scenarios, private Collection<IOIOConnectionBootstrap> bootstraps_ = IOIOConnectionRegistry
* where you want to identify which IOIO the thread is for. The provided .getBootstraps();
* arguments should provide enough information to be unique per connection. private IOIOConnectionFactory currentConnectionFactory_;
* <code>null</code> may be returned if the client is not interested to
* connect a thread for this IOIO. This can be used in order to filter out /**
* unwanted connections, for example if the application is only intended for * Subclasses should call this method from their own onCreate() if
* wireless connection, any wired connection attempts may be rejected, thus * overloaded. It takes care of connecting with the IOIO.
* saving resources used for listening for incoming wired connections. */
* @Override
* @param connectionClass protected void onCreate(Bundle savedInstanceState) {
* The fully-qualified name of the connection class used to super.onCreate(savedInstanceState);
* connect to the IOIO. for (IOIOConnectionBootstrap bootstrap : bootstraps_) {
* @param connectionArgs if (bootstrap instanceof ContextWrapperDependent) {
* A list of arguments passed to the constructor of the ((ContextWrapperDependent) bootstrap).onCreate(this);
* connection class. Should provide information that enables }
* distinguishing between different IOIO instances using the same }
* connection class. }
*
* @return An implementation of {@link IOIOThread}, or <code>null</code> to /**
* skip. * Subclasses should call this method from their own onDestroy() if
*/ * overloaded. It takes care of connecting with the IOIO.
protected IOIOThread createIOIOThread(String connectionClass, */
Object[] connectionArgs) { @Override
return createIOIOThread(); protected void onDestroy() {
} for (IOIOConnectionBootstrap bootstrap : bootstraps_) {
if (bootstrap instanceof ContextWrapperDependent) {
/** ((ContextWrapperDependent) bootstrap).onDestroy();
* An abstract class, which facilitates a thread dedicated for communication }
* with a single physical IOIO device. }
*/ super.onDestroy();
protected abstract class IOIOThread extends Thread { }
/** Subclasses should use this field for controlling the IOIO. */
protected IOIO ioio_; /**
private boolean abort_ = false; * Subclasses should call this method from their own onStart() if
private boolean connected_ = true; * overloaded. It takes care of connecting with the IOIO.
private final IOIOConnectionSpec spec_ = currentSpec_; */
@Override
/** protected void onStart() {
* Subclasses should override this method for performing operations to super.onStart();
* be done once as soon as IOIO communication is established. Typically, for (IOIOConnectionBootstrap bootstrap : bootstraps_) {
* this will include opening pins and modules using the openXXX() if (bootstrap instanceof ContextWrapperDependent) {
* methods of the {@link #ioio_} field. ((ContextWrapperDependent) bootstrap).open();
*/ }
protected void setup() throws ConnectionLostException, }
InterruptedException { createAllThreads();
} startAllThreads();
}
/**
* Subclasses should override this method for performing operations to /**
* be done repetitively as long as IOIO communication persists. * Subclasses should call this method from their own onStop() if overloaded.
* Typically, this will be the main logic of the application, processing * It takes care of disconnecting from the IOIO.
* inputs and producing outputs. */
*/ @Override
protected void loop() throws ConnectionLostException, protected void onStop() {
InterruptedException { abortAllThreads();
sleep(100000); try {
} joinAllThreads();
} catch (InterruptedException e) {
/** }
* Subclasses should override this method for performing operations to for (IOIOConnectionBootstrap bootstrap : bootstraps_) {
* be done once as soon as IOIO communication is lost or closed. if (bootstrap instanceof ContextWrapperDependent) {
* Typically, this will include GUI changes corresponding to the change. ((ContextWrapperDependent) bootstrap).close();
* This method will only be called if setup() has been called. The }
* {@link #ioio_} member must not be used from within this method. }
*/ super.onStop();
protected void disconnected() throws InterruptedException { }
}
@Override
/** protected void onNewIntent(Intent intent) {
* Subclasses should override this method for performing operations to super.onNewIntent(intent);
* be done if an incompatible IOIO firmware is detected. The if ((intent.getFlags() & Intent.FLAG_ACTIVITY_NEW_TASK) != 0) {
* {@link #ioio_} member must not be used from within this method. This for (IOIOConnectionBootstrap bootstrap : bootstraps_) {
* method will only be called once, until a compatible IOIO is connected if (bootstrap instanceof ContextWrapperDependent) {
* (i.e. {@link #setup()} gets called). ((ContextWrapperDependent) bootstrap).open();
*/ }
protected void incompatible() { }
} }
}
/** Not relevant to subclasses. */
@Override /**
public final void run() { * Subclasses must either implement this method or its other overload by
super.run(); * returning a concrete subclass of {@link IOIOThread}. <code>null</code>
Looper.prepare(); * may be returned if the client is not interested to create a thread for
while (true) { * this IOIO. In multi-IOIO scenarios, where you want to identify which IOIO
try { * the thread is for, consider using {@link #createIOIOThread()} instead.
synchronized (this) { *
if (abort_) { * @return An implementation of {@link IOIOThread}, or <code>null</code> to
break; * skip.
} */
ioio_ = IOIOFactory.create(spec_.className, spec_.args); protected IOIOThread createIOIOThread() {
} throw new RuntimeException(
ioio_.waitForConnect(); "Client must override on of the createIOIOThread overloads!");
connected_ = true; }
setup();
while (!abort_) { /**
loop(); * Subclasses should implement this method by returning a concrete subclass
} * of {@link IOIOThread}. This overload is useful in multi-IOIO scenarios,
ioio_.disconnect(); * where you want to identify which IOIO the thread is for. The provided
} catch (ConnectionLostException e) { * arguments should provide enough information to be unique per connection.
if (abort_) { * <code>null</code> may be returned if the client is not interested to
break; * connect a thread for this IOIO. This can be used in order to filter out
} * unwanted connections, for example if the application is only intended for
} catch (InterruptedException e) { * wireless connection, any wired connection attempts may be rejected, thus
ioio_.disconnect(); * saving resources used for listening for incoming wired connections.
break; *
} catch (IncompatibilityException e) { * @param connectionType
Log.e(TAG, "Incompatible IOIO firmware", e); * A unique name of the connection type. Typically, the
incompatible(); * fully-qualified name of the connection class used to connect
// nothing to do - just wait until physical disconnection * to the IOIO.
try { * @param extra
ioio_.waitForDisconnect(); * A connection-type-specific object with extra information on
} catch (InterruptedException e1) { * the specific connection. Should provide information that
ioio_.disconnect(); * enables distinguishing between different IOIO instances using
} * the same connection class. For example, a Bluetooth connection
} catch (Exception e) { * type, might have the remote IOIO's Bluetooth name as extra.
Log.e(TAG, "Unexpected exception caught", e); *
ioio_.disconnect(); * @return An implementation of {@link IOIOThread}, or <code>null</code> to
break; * skip.
} finally { */
try { protected IOIOThread createIOIOThread(String connectionType, Object extra) {
if (ioio_ != null) { return createIOIOThread();
ioio_.waitForDisconnect(); }
if (connected_) {
disconnected(); /**
} * An abstract class, which facilitates a thread dedicated for communication
} * with a single physical IOIO device.
} catch (InterruptedException e) { */
} protected abstract class IOIOThread extends Thread {
} /** Subclasses should use this field for controlling the IOIO. */
} protected IOIO ioio_;
} private boolean abort_ = false;
private boolean connected_ = true;
/** Not relevant to subclasses. */ private final IOIOConnectionFactory connectionFactory_ = currentConnectionFactory_;
public synchronized final void abort() {
abort_ = true; /**
if (ioio_ != null) { * Subclasses should override this method for performing operations to
ioio_.disconnect(); * be done once as soon as IOIO communication is established. Typically,
} * this will include opening pins and modules using the openXXX()
if (connected_) { * methods of the {@link #ioio_} field.
interrupt(); */
} protected void setup() throws ConnectionLostException,
} InterruptedException {
} }
private void abortAllThreads() { /**
for (IOIOThread thread : threads_) { * Subclasses should override this method for performing operations to
thread.abort(); * be done repetitively as long as IOIO communication persists.
} * Typically, this will be the main logic of the application, processing
} * inputs and producing outputs.
*/
private void joinAllThreads() throws InterruptedException { protected void loop() throws ConnectionLostException,
for (IOIOThread thread : threads_) { InterruptedException {
thread.join(); sleep(100000);
} }
}
/**
private void createAllThreads() { * Subclasses should override this method for performing operations to
threads_.clear(); * be done once as soon as IOIO communication is lost or closed.
Collection<IOIOConnectionSpec> specs = getConnectionSpecs(); * Typically, this will include GUI changes corresponding to the change.
for (IOIOConnectionSpec spec : specs) { * This method will only be called if setup() has been called. The
currentSpec_ = spec; * {@link #ioio_} member must not be used from within this method. This
IOIOThread thread = createIOIOThread(spec.className, spec.args); * method should not block for long, since it may cause an ANR.
if (thread != null) { */
threads_.add(thread); protected void disconnected() {
} }
}
} /**
* Subclasses should override this method for performing operations to
private void startAllThreads() { * be done if an incompatible IOIO firmware is detected. The
for (IOIOThread thread : threads_) { * {@link #ioio_} member must not be used from within this method. This
thread.start(); * method will only be called once, until a compatible IOIO is connected
} * (i.e. {@link #setup()} gets called).
} */
protected void incompatible() {
private Collection<IOIOConnectionSpec> getConnectionSpecs() { }
Collection<IOIOConnectionSpec> result = new LinkedList<IOIOConnectionSpec>();
addConnectionSpecs("ioio.lib.util.SocketIOIOConnectionDiscovery", /** Not relevant to subclasses. */
result); @Override
addConnectionSpecs( public final void run() {
"ioio.lib.bluetooth.BluetoothIOIOConnectionDiscovery", result); super.run();
return result; while (!abort_) {
} try {
synchronized (this) {
private void addConnectionSpecs(String discoveryClassName, if (abort_) {
Collection<IOIOConnectionSpec> result) { break;
try { }
Class<?> cls = Class.forName(discoveryClassName); ioio_ = IOIOFactory.create(connectionFactory_
IOIOConnectionDiscovery discovery = (IOIOConnectionDiscovery) cls .createConnection());
.newInstance(); }
discovery.getSpecs(result); } catch (Exception e) {
} catch (ClassNotFoundException e) { Log.e(TAG, "Failed to create IOIO, aborting IOIOThread!");
Log.d(TAG, "Discovery class not found: " + discoveryClassName return;
+ ". Not adding."); }
} catch (Exception e) { // if we got here, we have a ioio_!
Log.w(TAG, try {
"Exception caught while discovering connections - not adding connections of class " ioio_.waitForConnect();
+ discoveryClassName, e); connected_ = true;
} setup();
} while (!abort_) {
} loop();
}
} catch (ConnectionLostException e) {
} catch (InterruptedException e) {
ioio_.disconnect();
} catch (IncompatibilityException e) {
Log.e(TAG, "Incompatible IOIO firmware", e);
incompatible();
// nothing to do - just wait until physical disconnection
} catch (Exception e) {
Log.e(TAG, "Unexpected exception caught", e);
ioio_.disconnect();
break;
} finally {
try {
ioio_.waitForDisconnect();
} catch (InterruptedException e1) {
}
synchronized (this) {
ioio_ = null;
}
if (connected_) {
disconnected();
connected_ = false;
}
}
}
Log.d(TAG, "IOIOThread is exiting");
}
/** Not relevant to subclasses. */
public synchronized final void abort() {
abort_ = true;
if (ioio_ != null) {
ioio_.disconnect();
}
if (connected_) {
interrupt();
}
}
}
private void abortAllThreads() {
for (IOIOThread thread : threads_) {
thread.abort();
}
}
private void joinAllThreads() throws InterruptedException {
for (IOIOThread thread : threads_) {
thread.join();
}
}
private void createAllThreads() {
threads_.clear();
Collection<IOIOConnectionFactory> factories = IOIOConnectionRegistry
.getConnectionFactories();
for (IOIOConnectionFactory factory : factories) {
currentConnectionFactory_ = factory;
IOIOThread thread = createIOIOThread(factory.getType(),
factory.getExtra());
if (thread != null) {
threads_.add(thread);
}
}
}
private void startAllThreads() {
for (IOIOThread thread : threads_) {
thread.start();
}
}
}

View File

@@ -0,0 +1,48 @@
package ioio.lib.util;
import ioio.lib.api.IOIO;
import ioio.lib.api.exception.ConnectionLostException;
/**
* A convenience implementation of {@link IOIOLooper}.
*
* This base class provides no-op implementations for all methods and provides
* the {@link #ioio_} field for subclasses.
*
*/
public class BaseIOIOLooper implements IOIOLooper {
protected IOIO ioio_;
@Override
public final void setup(IOIO ioio) throws ConnectionLostException,
InterruptedException {
ioio_ = ioio;
setup();
}
/**
* This method will be called as soon as connection to the IOIO has been
* established. Typically, this will include opening pins and modules using
* the openXXX() methods of the {@link #ioio_} field.
*
* @throws ConnectionLostException
* The connection to the IOIO has been lost.
* @throws InterruptedException
* The thread has been interrupted.
*/
protected void setup() throws ConnectionLostException, InterruptedException {
}
@Override
public void loop() throws ConnectionLostException, InterruptedException {
Thread.sleep(20);
}
@Override
public void disconnected() {
}
@Override
public void incompatible() {
}
}

View File

@@ -0,0 +1,166 @@
package ioio.lib.util;
import ioio.lib.api.IOIO;
import ioio.lib.api.IOIOFactory;
import ioio.lib.api.exception.ConnectionLostException;
import ioio.lib.api.exception.IncompatibilityException;
import ioio.lib.spi.IOIOConnectionBootstrap;
import ioio.lib.spi.IOIOConnectionFactory;
import java.util.Collection;
import java.util.LinkedList;
import android.util.Log;
/**
* A helper class for creating different kinds of IOIO based applications.
*
* This class implements a common life-cycle for applications interacting with
* IOIO devices.
* <p>
* When the application starts, call {@link #start()}, which will in turn
* attempt to create a thread for each possible IOIO connection channel. Each
* thread will have a respective {@link IOIOLooper}, which the client provides,
* through which the client gets context for working with the IOIO.
* <p>
* When the application exits, call {@link #stop()}, which will disconnect all
* open connections and will abort and join all the threads.
*
*/
public class IOIOApplicationHelper {
/**
* An abstract class, which facilitates a thread dedicated for communication
* with a single physical IOIO device.
*/
static private class IOIOThread extends Thread {
protected IOIO ioio_;
private boolean abort_ = false;
private boolean connected_ = true;
private final IOIOLooper looper_;
private final IOIOConnectionFactory connectionFactory_;
IOIOThread(IOIOLooper looper, IOIOConnectionFactory factory) {
looper_ = looper;
connectionFactory_ = factory;
}
@Override
public final void run() {
super.run();
while (!abort_) {
try {
synchronized (this) {
if (abort_) {
break;
}
ioio_ = IOIOFactory.create(connectionFactory_
.createConnection());
}
} catch (Exception e) {
Log.e(TAG, "Failed to create IOIO, aborting IOIOThread!");
return;
}
// if we got here, we have a ioio_!
try {
ioio_.waitForConnect();
connected_ = true;
looper_.setup(ioio_);
while (!abort_ && ioio_.getState() == IOIO.State.CONNECTED) {
looper_.loop();
}
} catch (ConnectionLostException e) {
} catch (InterruptedException e) {
ioio_.disconnect();
} catch (IncompatibilityException e) {
Log.e(TAG, "Incompatible IOIO firmware", e);
looper_.incompatible();
// nothing to do - just wait until physical
// disconnection
} catch (Exception e) {
Log.e(TAG, "Unexpected exception caught", e);
ioio_.disconnect();
break;
} finally {
try {
ioio_.waitForDisconnect();
} catch (InterruptedException e1) {
}
synchronized (this) {
ioio_ = null;
}
if (connected_) {
looper_.disconnected();
connected_ = false;
}
}
}
Log.d(TAG, "IOIOThread is exiting");
}
/** Not relevant to subclasses. */
public synchronized final void abort() {
abort_ = true;
if (ioio_ != null) {
ioio_.disconnect();
}
if (connected_) {
interrupt();
}
}
}
protected static final String TAG = "IOIOAndroidApplicationHelper";
protected final IOIOLooperProvider looperProvider_;
private Collection<IOIOThread> threads_ = new LinkedList<IOIOThread>();
protected Collection<IOIOConnectionBootstrap> bootstraps_ = IOIOConnectionRegistry
.getBootstraps();
public IOIOApplicationHelper(IOIOLooperProvider provider) {
looperProvider_ = provider;
}
protected void abortAllThreads() {
for (IOIOThread thread : threads_) {
thread.abort();
}
}
protected void joinAllThreads() throws InterruptedException {
for (IOIOThread thread : threads_) {
thread.join();
}
}
protected void createAllThreads() {
threads_.clear();
Collection<IOIOConnectionFactory> factories = IOIOConnectionRegistry
.getConnectionFactories();
for (IOIOConnectionFactory factory : factories) {
IOIOLooper looper = looperProvider_.createIOIOLooper(
factory.getType(), factory.getExtra());
if (looper != null) {
threads_.add(new IOIOThread(looper, factory));
}
}
}
protected void startAllThreads() {
for (IOIOThread thread : threads_) {
thread.start();
}
}
public void start() {
createAllThreads();
startAllThreads();
}
public void stop() {
abortAllThreads();
try {
joinAllThreads();
} catch (InterruptedException e) {
}
}
}

View File

@@ -1,17 +0,0 @@
package ioio.lib.util;
import java.util.Collection;
public interface IOIOConnectionDiscovery {
public static class IOIOConnectionSpec {
public final String className;
public final Object[] args;
public IOIOConnectionSpec(String c, Object[] a) {
className = c;
args = a;
}
}
public void getSpecs(Collection<IOIOConnectionSpec> result);
}

View File

@@ -0,0 +1,133 @@
/*
* Copyright 2011 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.util;
import ioio.lib.api.IOIOConnection;
import ioio.lib.api.IOIOFactory;
import ioio.lib.spi.IOIOConnectionBootstrap;
import ioio.lib.spi.IOIOConnectionFactory;
import java.util.Collection;
import java.util.LinkedList;
import android.util.Log;
/**
* A utility class for managing available connection types to IOIO.
* <p>
* <b>For advanced usage only!</b>
* <p>
* This class facilitates dynamic linkage and instantiation of different IOIO
* connection types. {@link IOIOConnectionBootstrap} classes enable creation of
* {@link IOIOConnectionFactory} instances, from which concrete
* {@link IOIOConnection}s are created. The binding to
* {@link IOIOConnectionBootstrap} is dynamic, thus enabling linkage to succeed
* with or without those bootstraps. Likewise, during runtime, the absence of
* bootstraps is handled gracefully.
*
* A typical usage will call {@link #addBootstraps(String[])} with a list of
* class names to be sought from a static initializer block. It may then call
* {@link #getBootstraps()} to obtain any bootstrap classes that are available
* in runtime, in case the bootstrap classes themselves need some runtime
* handling. Last, the {@link #getConnectionFactories()} will return a
* collection of {@link IOIOConnectionFactory}, each representing one possible
* communication channel to a IOIO.
*
*/
public class IOIOConnectionRegistry {
/**
* Get all available connection specifications. This is a list of all
* currently available communication channels in which a IOIO may be
* available. The client typically passes elements of this collection to
* {@link IOIOFactory#create(IOIOConnection)}, possibly after filtering based on the
* specification's properties.
*
* @return A collection of specifications.
*/
public static Collection<IOIOConnectionFactory> getConnectionFactories() {
Collection<IOIOConnectionFactory> result = new LinkedList<IOIOConnectionFactory>();
for (IOIOConnectionBootstrap bootstrap : bootstraps_) {
bootstrap.getFactories(result);
}
return result;
}
/**
* For advanced usage only! Used for special runtime handling of bootstrap
* classes.
*
* @return The bootstraps.
*/
public static Collection<IOIOConnectionBootstrap> getBootstraps() {
return bootstraps_;
}
/**
* For advanced usage only! Add platform-specific connection bootstrap
* classes. Call before calling {@link #getConnectionFactories()}.
*/
public static void addBootstraps(String[] classNames) {
for (String className : classNames) {
addBootstrap(className);
}
}
private static final String TAG = "IOIOConnectionRegistry";
private static Collection<IOIOConnectionBootstrap> bootstraps_;
static {
bootstraps_ = new LinkedList<IOIOConnectionBootstrap>();
String[] classNames = new String[] { "ioio.lib.impl.SocketIOIOConnectionBootstrap" };
addBootstraps(classNames);
}
private static void addBootstrap(String className) {
try {
Class<? extends IOIOConnectionBootstrap> bootstrapClass = Class
.forName(className).asSubclass(
IOIOConnectionBootstrap.class);
bootstraps_.add(bootstrapClass.newInstance());
Log.d(TAG, "Successfully added bootstrap class: " + className);
} catch (ClassNotFoundException e) {
Log.d(TAG, "Bootstrap class not found: " + className
+ ". Not adding.");
} catch (RuntimeException e) {
Log.e(TAG,
"Runtime exception caught while attempting to initialize accessory connection factory",
e);
throw e;
} catch (Exception e) {
Log.w(TAG,
"Exception caught while attempting to initialize accessory connection factory",
e);
}
}
}

View File

@@ -0,0 +1,56 @@
package ioio.lib.util;
import ioio.lib.api.IOIO;
import ioio.lib.api.exception.ConnectionLostException;
/**
* A handler implementing interaction with a single IOIO over a single
* connection period. The interface utilizes a basic workflow for working with a
* IOIO instance: as soon as a connection is established, {@link #setup(IOIO)}
* will be called. Then, the {@link #loop()} method will be called repeatedly as
* long as the connection is alive. Last, the {@link #disconnected()} method
* will be called upon losing the connection (as result of physical
* disconnection, closing the application, etc). In case a IOIO with an
* incompatible firmware is encountered, {@link #incompatible()} will be called
* instead of {@link #setup(IOIO)}, and the IOIO instance is entirely useless,
* until eventually {@link #disconnected()} gets called.
*
*/
public interface IOIOLooper {
/**
* Subclasses should override this method for performing operations to be
* done once as soon as IOIO communication is established.
*/
public abstract void setup(IOIO ioio) throws ConnectionLostException,
InterruptedException;
/**
* Subclasses should override this method for performing operations to be
* done repetitively as long as IOIO communication persists. Typically, this
* will be the main logic of the application, processing inputs and
* producing outputs.
*/
public abstract void loop() throws ConnectionLostException,
InterruptedException;
/**
* Subclasses should override this method for performing operations to be
* done once as soon as IOIO communication is lost or closed. Typically,
* this will include GUI changes corresponding to the change. This method
* will only be called if setup() has been called. The ioio argument passed
* to {@link #setup(IOIO)} must not be used from within this method - it is
* invalid. This method should not block for long, since it may cause an
* ANR.
*/
public abstract void disconnected();
/**
* Subclasses should override this method for performing operations to be
* done if an incompatible IOIO firmware is detected. The ioio argument
* passed to {@link #setup(IOIO)} must not be used from within this method -
* it is invalid. This method will only be called once, until a compatible
* IOIO is connected (i.e. {@link #setup(IOIO)} gets called).
*/
public abstract void incompatible();
}

View File

@@ -0,0 +1,36 @@
package ioio.lib.util;
/**
* An entity that provides {@link IOIOLooper} instances on demand, per
* connection specifications.
*/
public interface IOIOLooperProvider {
/**
* Subclasses should implement this method by returning an implementation of
* {@link IOIOLooper}. The caller provide enough information to uniquely
* identify the connection, through the parameters. <code>null</code> may be
* returned if the client is not interested to create a thread for this
* IOIO. This can be used in order to filter out unwanted connections, for
* example if the application is only intended for wireless connection, any
* wired connection attempts may be rejected, thus saving resources used for
* listening for incoming wired connections.
*
* @param connectionType
* A unique name of the connection type. Typically, the
* fully-qualified name of the connection class used to connect
* to the IOIO.
* @param extra
* A connection-type-specific object with extra information on
* the specific connection. Should provide information that
* enables distinguishing between different IOIO instances using
* the same connection class. For example, a Bluetooth connection
* type, might have the remote IOIO's Bluetooth name as extra.
*
* @return An implementation of {@link IOIOLooper}, or <code>null</code> to
* skip.
*/
public abstract IOIOLooper createIOIOLooper(String connectionType,
Object extra);
}

View File

@@ -1,15 +0,0 @@
package ioio.lib.util;
import ioio.lib.api.IOIOFactory;
import ioio.lib.impl.SocketIOIOConnection;
import java.util.Collection;
public class SocketIOIOConnectionDiscovery implements IOIOConnectionDiscovery {
@Override
public void getSpecs(Collection<IOIOConnectionSpec> result) {
result.add(new IOIOConnectionSpec(SocketIOIOConnection.class.getName(),
new Object[] { new Integer(IOIOFactory.IOIO_PORT) }));
}
}

View File

@@ -0,0 +1,41 @@
/*
* Copyright 2011 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.util.android;
import android.content.ContextWrapper;
public interface ContextWrapperDependent {
public void onCreate(ContextWrapper wrapper);
public void onDestroy();
public void open();
public void reopen();
public void close();
}

View File

@@ -0,0 +1,148 @@
/*
* Copyright 2011 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.util.android;
import ioio.lib.impl.SocketIOIOConnection;
import ioio.lib.util.IOIOLooper;
import ioio.lib.util.IOIOLooperProvider;
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
/**
* A convenience class for easy creation of IOIO-based activities.
*
* It is used by creating a concrete {@link Activity} in your application, which
* extends this class. This class then takes care of proper creation and
* abortion of the IOIO connection and of a dedicated thread for IOIO
* communication.
* <p>
* In the basic usage the client should extend this class and implement
* {@link #createIOIOLooper()}, which should return an implementation of the
* {@link IOIOLooper} interface. In this implementation, the client implements
* the {@link IOIOLooper#setup(ioio.lib.api.IOIO)} method, which gets called as
* soon as communication with the IOIO is established, and the
* {@link IOIOLooper#loop()} method, which gets called repetitively as long as
* the IOIO is connected.
* <p>
* In addition, the {@link IOIOLooper#disconnected()} method may be overridden
* in order to execute logic as soon as a disconnection occurs for whichever
* reason. The {@link IOIOLooper#incompatible()} method may be overridden in
* order to take action in case where a IOIO whose firmware is incompatible with
* the IOIOLib version that application is built with.
* <p>
* In a more advanced use case, more than one IOIO is available. In this case, a
* thread will be created for each IOIO, whose semantics are as defined above.
* If the client needs to be able to distinguish between them, it is possible to
* override {@link #createIOIOLooper(String, Object)} instead of
* {@link #createIOIOLooper()}. The first argument provided will contain the
* connection class name, such as ioio.lib.impl.SocketIOIOConnection for a
* connection established over a TCP socket (which is used over ADB). The second
* argument will contain information specific to the connection type. For
* example, in the case of {@link SocketIOIOConnection}, the second argument
* will contain an {@link Integer} representing the local port number.
*/
public abstract class IOIOActivity extends Activity implements
IOIOLooperProvider {
private final IOIOAndroidApplicationHelper helper_ = new IOIOAndroidApplicationHelper(
this, this);
/**
* Subclasses should call this method from their own onCreate() if
* overloaded. It takes care of connecting with the IOIO.
*/
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
helper_.create();
}
/**
* Subclasses should call this method from their own onDestroy() if
* overloaded. It takes care of connecting with the IOIO.
*/
@Override
protected void onDestroy() {
helper_.destroy();
super.onDestroy();
}
/**
* Subclasses should call this method from their own onStart() if
* overloaded. It takes care of connecting with the IOIO.
*/
@Override
protected void onStart() {
super.onStart();
helper_.start();
}
/**
* Subclasses should call this method from their own onStop() if overloaded.
* It takes care of disconnecting from the IOIO.
*/
@Override
protected void onStop() {
helper_.stop();
super.onStop();
}
@Override
protected void onNewIntent(Intent intent) {
super.onNewIntent(intent);
if ((intent.getFlags() & Intent.FLAG_ACTIVITY_NEW_TASK) != 0) {
helper_.restart();
}
}
/**
* Subclasses must either implement this method or its other overload by
* returning an implementation of {@link IOIOLooper}. A dedicated thread
* will be created for each available IOIO, from which the
* {@link IOIOLooper}'s methods will be invoked. <code>null</code> may be
* returned if the client is not interested to create a thread for this
* IOIO. In multi-IOIO scenarios, where you want to identify which IOIO the
* thread is for, consider overriding
* {@link #createIOIOLooper(String, Object)} instead.
*
* @return An implementation of {@link IOIOLooper}, or <code>null</code> to
* skip.
*/
protected IOIOLooper createIOIOLooper() {
throw new RuntimeException(
"Client must override one of the createIOIOLooper overloads!");
}
@Override
public IOIOLooper createIOIOLooper(String connectionType, Object extra) {
return createIOIOLooper();
}
}

View File

@@ -0,0 +1,69 @@
package ioio.lib.util.android;
import ioio.lib.spi.IOIOConnectionBootstrap;
import ioio.lib.util.IOIOApplicationHelper;
import ioio.lib.util.IOIOConnectionRegistry;
import ioio.lib.util.IOIOLooperProvider;
import android.content.ContextWrapper;
public class IOIOAndroidApplicationHelper extends IOIOApplicationHelper {
private final ContextWrapper contextWrapper_;
public IOIOAndroidApplicationHelper(ContextWrapper wrapper,
IOIOLooperProvider provider) {
super(provider);
contextWrapper_ = wrapper;
}
static {
IOIOConnectionRegistry
.addBootstraps(new String[] {
"ioio.lib.android.accessory.AccessoryConnectionBootstrap",
"ioio.lib.android.bluetooth.BluetoothIOIOConnectionBootstrap" });
}
public void create() {
for (IOIOConnectionBootstrap bootstrap : bootstraps_) {
if (bootstrap instanceof ContextWrapperDependent) {
((ContextWrapperDependent) bootstrap).onCreate(contextWrapper_);
}
}
}
public void destroy() {
for (IOIOConnectionBootstrap bootstrap : bootstraps_) {
if (bootstrap instanceof ContextWrapperDependent) {
((ContextWrapperDependent) bootstrap).onDestroy();
}
}
}
@Override
public void start() {
for (IOIOConnectionBootstrap bootstrap : bootstraps_) {
if (bootstrap instanceof ContextWrapperDependent) {
((ContextWrapperDependent) bootstrap).open();
}
}
super.start();
}
@Override
public void stop() {
super.stop();
for (IOIOConnectionBootstrap bootstrap : bootstraps_) {
if (bootstrap instanceof ContextWrapperDependent) {
((ContextWrapperDependent) bootstrap).close();
}
}
}
public void restart() {
for (IOIOConnectionBootstrap bootstrap : bootstraps_) {
if (bootstrap instanceof ContextWrapperDependent) {
((ContextWrapperDependent) bootstrap).reopen();
}
}
}
}

View File

@@ -0,0 +1,149 @@
/*
* Copyright 2011 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.util.android;
import ioio.lib.impl.SocketIOIOConnection;
import ioio.lib.util.IOIOLooper;
import ioio.lib.util.IOIOLooperProvider;
import android.app.Service;
import android.content.Intent;
/**
* A convenience class for easy creation of IOIO-based services.
*
* It is used by creating a concrete {@link Service} in your application, which
* extends this class. This class then takes care of proper creation and
* abortion of the IOIO connection and of a dedicated thread for IOIO
* communication.
* <p>
* In the basic usage the client should extend this class and implement
* {@link #createIOIOLooper()}, which should return an implementation of the
* {@link IOIOLooper} interface. In this implementation, the client implements
* the {@link IOIOLooper#setup(ioio.lib.api.IOIO)} method, which gets called as
* soon as communication with the IOIO is established, and the
* {@link IOIOLooper#loop()} method, which gets called repetitively as long as
* the IOIO is connected.
* <p>
* In addition, the {@link IOIOLooper#disconnected()} method may be overridden
* in order to execute logic as soon as a disconnection occurs for whichever
* reason. The {@link IOIOLooper#incompatible()} method may be overridden in
* order to take action in case where a IOIO whose firmware is incompatible with
* the IOIOLib version that application is built with.
* <p>
* In a more advanced use case, more than one IOIO is available. In this case, a
* thread will be created for each IOIO, whose semantics are as defined above.
* If the client needs to be able to distinguish between them, it is possible to
* override {@link #createIOIOLooper(String, Object)} instead of
* {@link #createIOIOLooper()}. The first argument provided will contain the
* connection class name, such as ioio.lib.impl.SocketIOIOConnection for a
* connection established over a TCP socket (which is used over ADB). The second
* argument will contain information specific to the connection type. For
* example, in the case of {@link SocketIOIOConnection}, the second argument
* will contain an {@link Integer} representing the local port number.
*/
public abstract class IOIOService extends Service implements
IOIOLooperProvider {
private final IOIOAndroidApplicationHelper helper_ = new IOIOAndroidApplicationHelper(
this, this);
private boolean started_ = false;
/**
* Subclasses should call this method from their own onCreate() if
* overloaded. It takes care of connecting with the IOIO.
*/
@Override
public void onCreate() {
super.onCreate();
helper_.create();
}
/**
* Subclasses should call this method from their own onDestroy() if
* overloaded. It takes care of connecting with the IOIO.
*/
@Override
public void onDestroy() {
stop();
helper_.destroy();
super.onDestroy();
}
/**
* Subclasses should call this method from their own onStart() if
* overloaded. It takes care of connecting with the IOIO.
*/
@Override
public void onStart(Intent intent, int startId) {
super.onStart(intent, startId);
if (!started_) {
helper_.start();
started_ = true;
} else {
if ((intent.getFlags() & Intent.FLAG_ACTIVITY_NEW_TASK) != 0) {
helper_.restart();
}
}
}
/**
* Subclasses should call this method if they wish to disconnect from the
* IOIO(s) until the next onStart().
*/
protected void stop() {
if (started_) {
helper_.stop();
started_ = false;
}
}
/**
* Subclasses must either implement this method or its other overload by
* returning an implementation of {@link IOIOLooper}. A dedicated thread
* will be created for each available IOIO, from which the
* {@link IOIOLooper}'s methods will be invoked. <code>null</code> may be
* returned if the client is not interested to create a thread for this
* IOIO. In multi-IOIO scenarios, where you want to identify which IOIO the
* thread is for, consider overriding
* {@link #createIOIOLooper(String, Object)} instead.
*
* @return An implementation of {@link IOIOLooper}, or <code>null</code> to
* skip.
*/
protected IOIOLooper createIOIOLooper() {
throw new RuntimeException(
"Client must override one of the createIOIOLooper overloads!");
}
@Override
public IOIOLooper createIOIOLooper(String connectionType, Object extra) {
return createIOIOLooper();
}
}