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:
*
* <pre>
* {@code
* AnalogInput potentiometer = ioio.openAnalogInput(40);
* float value = potentiometer.read();
* ...
* 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>
*
* @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
* interrupted.
* <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.
* @throws InterruptedException The calling thread has been interrupted.
* @throws ConnectionLostException The connection with the IOIO is lost.
* @throws InterruptedException
* The calling thread has been interrupted.
* @throws ConnectionLostException
* The connection with the IOIO is lost.
* @see #read()
*/
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.
*
* @return The voltage, in Volts.
*/
public float getReference();
@@ -96,9 +131,95 @@ public interface AnalogInput extends Closeable {
* If an absolute value is desired, consider using {@link #getVoltage()}.
*
* @return The voltage, in scaled units.
* @throws InterruptedException The calling thread has been interrupted.
* @throws ConnectionLostException The connection with the IOIO is lost.
* @throws InterruptedException
* The calling thread has been interrupted.
* @throws ConnectionLostException
* The connection with the IOIO is lost.
* @see #getVoltage()
*/
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.
*
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
* of conditions and the following disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL ARSHAN POURSOHI OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* The views and conclusions contained in the software and documentation are those of the
* authors and should not be interpreted as representing official policies, either expressed
* or implied.
*/
package ioio.lib.api;
import ioio.lib.api.exception.ConnectionLostException;
/**
* A pin used for digital input.
* <p>
* A digital input pin can be used to read logic-level signals. DigitalInput
* instances are obtained by calling {@link IOIO#openDigitalInput(Spec)}.
* <p>
* 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
* {@link #waitForValue(boolean)}.
* <p>
* 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
* connection with the IOIO 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 {@link ConnectionLostException}. Whenever
* {@link #close()} is invoked the instance may no longer be used. Any resources
* associated with it are freed and can be reused.
* <p>
* Typical usage:
*
* <pre>
* DigitalInput button = ioio.openDigitalInput(10); // used an external pull-up
* button.waitForValue(false); // wait for press
* ...
* button.close(); // pin 10 can now be used for something else.
* </pre>
*/
public interface DigitalInput extends Closeable {
/**
* A digital input pin specification, used when opening digital inputs.
*/
static public class Spec {
/** Input pin mode. */
public enum Mode {
/**
* Pin is floating. When the pin is left disconnected the value
* sensed is undefined. Use this mode when an external pull-up or
* pull-down resistor is used or when interfacing push-pull type
* logic circuits.
*/
FLOATING,
/**
* Internal pull-up resistor is used. When the pin is left
* disconnected, a logical "HIGH" (true) will be sensed. This is
* useful for interfacing with open drain circuits or for
* interacting with a switch connected between the pin and ground.
*/
PULL_UP,
/**
* Internal pull-down resistor is used. When the pin is left
* disconnected, a logical "LOW" (false) will be sensed. This is
* useful for interacting with a switch connected between the pin
* and Vdd.
*/
PULL_DOWN
}
/** The pin number, as labeled on the board. */
public int pin;
/** The pin mode. */
public Mode mode;
/**
* Constructor.
*
* @param pin
* Pin number, as labeled on the board.
* @param mode
* Pin mode.
*/
public Spec(int pin, Mode mode) {
this.pin = pin;
this.mode = mode;
}
/** Shorthand for Spec(pin, Mode.FLOATING). */
public Spec(int pin) {
this(pin, Mode.FLOATING);
}
}
/**
* 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
* calling thread may be interrupted.
*
* @return True for logical "HIGH", false for logical "LOW".
* @throws InterruptedException
* The calling thread has been interrupted.
* @throws ConnectionLostException
* The connection with the IOIO has been lost.
*/
public boolean read() throws InterruptedException, ConnectionLostException;
/**
* Block until a desired logical level is sensed. The calling thread can be
* interrupted for aborting this operation.
*
* @param value
* The desired logical level. true for "HIGH", false for "LOW".
* @throws InterruptedException
* The calling thread has been interrupted.
* @throws ConnectionLostException
* The connection with the IOIO has been lost.
*/
public void waitForValue(boolean value) throws InterruptedException,
ConnectionLostException;
}
/*
* 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.api;
import ioio.lib.api.exception.ConnectionLostException;
/**
* A pin used for digital input.
* <p>
* A digital input pin can be used to read logic-level signals. DigitalInput
* instances are obtained by calling {@link IOIO#openDigitalInput(DigitalInput.Spec)}.
* <p>
* 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
* {@link #waitForValue(boolean)}.
* <p>
* 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
* connection with the IOIO 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 {@link ConnectionLostException}. Whenever
* {@link #close()} is invoked the instance may no longer be used. Any resources
* associated with it are freed and can be reused.
* <p>
* Typical usage:
*
* <pre>
* DigitalInput button = ioio.openDigitalInput(10); // used an external pull-up
* button.waitForValue(false); // wait for press
* ...
* button.close(); // pin 10 can now be used for something else.
* </pre>
*/
public interface DigitalInput extends Closeable {
/**
* A digital input pin specification, used when opening digital inputs.
*/
static public class Spec {
/** Input pin mode. */
public enum Mode {
/**
* Pin is floating. When the pin is left disconnected the value
* sensed is undefined. Use this mode when an external pull-up or
* pull-down resistor is used or when interfacing push-pull type
* logic circuits.
*/
FLOATING,
/**
* Internal pull-up resistor is used. When the pin is left
* disconnected, a logical "HIGH" (true) will be sensed. This is
* useful for interfacing with open drain circuits or for
* interacting with a switch connected between the pin and ground.
*/
PULL_UP,
/**
* Internal pull-down resistor is used. When the pin is left
* disconnected, a logical "LOW" (false) will be sensed. This is
* useful for interacting with a switch connected between the pin
* and Vdd.
*/
PULL_DOWN
}
/** The pin number, as labeled on the board. */
public int pin;
/** The pin mode. */
public Mode mode;
/**
* Constructor.
*
* @param pin
* Pin number, as labeled on the board.
* @param mode
* Pin mode.
*/
public Spec(int pin, Mode mode) {
this.pin = pin;
this.mode = mode;
}
/** Shorthand for Spec(pin, Mode.FLOATING). */
public Spec(int pin) {
this(pin, Mode.FLOATING);
}
}
/**
* 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
* calling thread may be interrupted.
*
* @return True for logical "HIGH", false for logical "LOW".
* @throws InterruptedException
* The calling thread has been interrupted.
* @throws ConnectionLostException
* The connection with the IOIO has been lost.
*/
public boolean read() throws InterruptedException, ConnectionLostException;
/**
* Block until a desired logical level is sensed. The calling thread can be
* interrupted for aborting this operation.
*
* @param value
* The desired logical level. true for "HIGH", false for "LOW".
* @throws InterruptedException
* The calling thread has been interrupted.
* @throws ConnectionLostException
* The connection with the IOIO has been lost.
*/
public void waitForValue(boolean value) throws InterruptedException,
ConnectionLostException;
}

View File

@@ -1,120 +1,120 @@
/*
* 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.api;
import ioio.lib.api.exception.ConnectionLostException;
/**
* A pin used for digital output.
* <p>
* A digital input pin can be used to generate logic-level signals.
* DigitalOutput instances are obtained by calling
* {@link IOIO#openDigitalOutput(Spec, boolean)}.
* <p>
* The value of the pin is set by calling {@link #write(boolean)}.
* <p>
* 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
* which every attempt to use the pin (except {@link #close()}) will throw a
* {@link ConnectionLostException}. Whenever {@link #close()} is invoked the
* instance may no longer be used. Any resources associated with it are freed
* and can be reused.
* <p>
* Typical usage:
*
* <pre>
* DigitalOutput led = ioio.openDigitalInput(2); // LED anode on pin 2.
* led.write(true); // turn LED on.
* ...
* led.close(); // pin 2 can now be used for something else.
* </pre>
*/
public interface DigitalOutput extends Closeable {
/**
* A digital output pin specification, used when opening digital outputs.
*/
public static class Spec {
/** Output pin mode. */
public enum Mode {
/**
* 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
* a voltage of 0 (ground).
*/
NORMAL,
/**
* Pin operates in open-drain mode, i.e. a logical "HIGH" is
* represented by a high impedance on the pin (as if it is
* disconnected) and a logical "LOW" by a voltage of 0 (ground).
* 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
* is connected between the pin and 5V, and the pin is used in open-
* drain mode.
*/
OPEN_DRAIN,
}
/** The pin number, as labeled on the board. */
public int pin;
/** The pin mode. */
public Mode mode;
/**
* Constructor.
*
* @param pin
* Pin number, as labeled on the board.
* @param mode
* Pin mode.
*/
public Spec(int pin, Mode mode) {
this.pin = pin;
this.mode = mode;
}
/**
* Shorthand for Spec(pin, Mode.NORMAL).
*
* @see #Spec(int, Mode)
*/
public Spec(int pin) {
this(pin, Mode.NORMAL);
}
}
/**
* Set the output of the pin.
*
* @param val
* The output. true is logical "HIGH", false is logical "LOW".
* @throws ConnectionLostException
* The connection with the IOIO has been lost.
*/
public void write(boolean val) throws ConnectionLostException;
}
/*
* 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.api;
import ioio.lib.api.exception.ConnectionLostException;
/**
* A pin used for digital output.
* <p>
* A digital input pin can be used to generate logic-level signals.
* DigitalOutput instances are obtained by calling
* {@link IOIO#openDigitalOutput(DigitalOutput.Spec, boolean)}.
* <p>
* The value of the pin is set by calling {@link #write(boolean)}.
* <p>
* 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
* which every attempt to use the pin (except {@link #close()}) will throw a
* {@link ConnectionLostException}. Whenever {@link #close()} is invoked the
* instance may no longer be used. Any resources associated with it are freed
* and can be reused.
* <p>
* Typical usage:
*
* <pre>
* DigitalOutput led = ioio.openDigitalInput(2); // LED anode on pin 2.
* led.write(true); // turn LED on.
* ...
* led.close(); // pin 2 can now be used for something else.
* </pre>
*/
public interface DigitalOutput extends Closeable {
/**
* A digital output pin specification, used when opening digital outputs.
*/
public static class Spec {
/** Output pin mode. */
public enum Mode {
/**
* 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
* a voltage of 0 (ground).
*/
NORMAL,
/**
* Pin operates in open-drain mode, i.e. a logical "HIGH" is
* represented by a high impedance on the pin (as if it is
* disconnected) and a logical "LOW" by a voltage of 0 (ground).
* 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
* is connected between the pin and 5V, and the pin is used in open-
* drain mode.
*/
OPEN_DRAIN,
}
/** The pin number, as labeled on the board. */
public int pin;
/** The pin mode. */
public Mode mode;
/**
* Constructor.
*
* @param pin
* Pin number, as labeled on the board.
* @param mode
* Pin mode.
*/
public Spec(int pin, Mode mode) {
this.pin = pin;
this.mode = mode;
}
/**
* Shorthand for Spec(pin, Mode.NORMAL).
*
* @see DigitalOutput.Spec#Spec(int, DigitalOutput.Spec.Mode)
*/
public Spec(int pin) {
this(pin, Mode.NORMAL);
}
}
/**
* Set the output of the pin.
*
* @param val
* The output. true is logical "HIGH", false is logical "LOW".
* @throws ConnectionLostException
* The connection with the IOIO has been lost.
*/
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;
import java.lang.reflect.Constructor;
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.
@@ -55,22 +59,21 @@ import ioio.lib.impl.SocketIOIOConnection;
* </pre>
*/
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
* instance which works with the actual IOIO board connected via a TCP
* connection (typically over a wired USB connection).
*
*
* @return The IOIO instance.
*/
public static IOIO create() {
Collection<IOIOConnectionFactory> factories = IOIOConnectionRegistry
.getConnectionFactories();
try {
return create(SocketIOIOConnection.class.getName(), IOIO_PORT);
} catch (ClassNotFoundException e) {
// we shouldn't get here - this class must always exist.
throw new RuntimeException("Something is very wrong here");
return create(factories.iterator().next().createConnection());
} catch (NoSuchElementException e) {
Log.e(TAG, "No connection is available. This shouldn't happen.");
throw e;
}
}
@@ -78,44 +81,15 @@ public class IOIOFactory {
* Create a IOIO instance with a user-provided underlying connection class.
* This method should be used for establishing a non-standard connection to
* the IOIO board.
*
* @param connectionClassName
* The name of the connection class. Must have a public default
* constructor.
*
*
* @param connection
* An instance of a IOIO connection.
*
* @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) {
return new IOIOImpl(connection);
}
public static IOIOConnection createConnectionDynamically(
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;
}
private static final String TAG = "IOIOFactory";
}

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.
* <p>
* {@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
* precision (single or double), the clock rate and the mode of operation. Modes
* 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;
import ioio.lib.api.DigitalInput.Spec;
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
* operate in pull-up mode, using either the internal pull-up or an external
* 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>
* 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
@@ -90,9 +89,11 @@ import ioio.lib.api.exception.ConnectionLostException;
* spi.writeRead(request, 2, 4, response, 3);
* ...
* 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 {
/** 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,
* false)
*
* @see #Config(Rate, boolean, boolean)
* @see SpiMaster.Config#Config(SpiMaster.Config.Rate, boolean, boolean)
*/
public Config(Rate rate) {
this(rate, false, false);
@@ -165,7 +166,7 @@ public interface SpiMaster extends Closeable {
* @param slave
* The slave index. It is determined by the index of its
* 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
* 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
* nodes, where the SDA is open-drain and externally pulled-up. TwiMaster
* instances are obtained by calling
* {@link IOIO#openTwiMaster(int, Rate, boolean)}.
* {@link IOIO#openTwiMaster(int, ioio.lib.api.TwiMaster.Rate, boolean)}.
* <p>
* TWI is the generic name for the specific I2C and SMBus protocols, differing
* 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
* }</pre>
*
* @see IOIO#openTwiMaster(int, Rate, boolean)
* @see IOIO#openTwiMaster(int, ioio.lib.api.TwiMaster.Rate, boolean)
*/
public interface TwiMaster extends Closeable {
enum Rate {

View File

@@ -1,108 +1,107 @@
/*
* 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.api;
import ioio.lib.api.DigitalInput.Spec;
import ioio.lib.api.exception.ConnectionLostException;
import java.io.InputStream;
import java.io.OutputStream;
/**
* An interface for controlling a UART module.
* <p>
* UART is a very common hardware communication protocol, enabling full- duplex,
* 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
* RS-485. Uart instances are obtained by calling
* {@link IOIO#openUart(Spec, ioio.lib.api.DigitalOutput.Spec, int, Parity, StopBits)}.
* <p>
* 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,
* making it very useful for terminals and terminal-controllable devices.
* <p>
* 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
* UART instances, by passing null (or INVALID_PIN) for either TX or RX pins.
* <p>
* 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
* every attempt to use it (except {@link #close()}) will throw a
* {@link ConnectionLostException}. Whenever {@link #close()} is invoked the
* instance may no longer be used. Any resources associated with it are freed
* and can be reused.
* <p>
* Typical usage:
*
* <pre>
* Uart uart = ioio.openUart(3, 4, 19200, Parity.NONE, StopBits.ONE);
* InputStream in = uart.getInputStream();
* OutputStream out = uart.getOutputStream();
* out.write(new String("Hello").getBytes());
* int i = in.read(); // blocking
* ...
* uart.close(); // free UART module and pins
* </pre>
*
* @see IOIO#openUart(Spec, ioio.lib.api.DigitalOutput.Spec, int, Parity,
* StopBits)
*/
public interface Uart extends Closeable {
/** Parity-bit mode. */
enum Parity {
/** No parity. */
NONE,
/** Even parity. */
EVEN,
/** Odd parity. */
ODD
}
/** Number of stop-bits. */
enum StopBits {
/** One stop bit. */
ONE,
/** Two stop bits. */
TWO
}
/**
* Gets the input stream.
*
* @return An input stream.
*/
public InputStream getInputStream();
/**
* Gets the output stream.
*
* @return An output stream.
*/
public OutputStream getOutputStream();
}
/*
* 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.api;
import ioio.lib.api.exception.ConnectionLostException;
import java.io.InputStream;
import java.io.OutputStream;
/**
* An interface for controlling a UART module.
* <p>
* UART is a very common hardware communication protocol, enabling full- duplex,
* 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
* RS-485. Uart instances are obtained by calling
* {@link IOIO#openUart(DigitalInput.Spec, DigitalOutput.Spec, int, Uart.Parity, Uart.StopBits)}.
* <p>
* 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,
* making it very useful for terminals and terminal-controllable devices.
* <p>
* 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
* UART instances, by passing null (or INVALID_PIN) for either TX or RX pins.
* <p>
* 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
* every attempt to use it (except {@link #close()}) will throw a
* {@link ConnectionLostException}. Whenever {@link #close()} is invoked the
* instance may no longer be used. Any resources associated with it are freed
* and can be reused.
* <p>
* Typical usage:
*
* <pre>
* Uart uart = ioio.openUart(3, 4, 19200, Parity.NONE, StopBits.ONE);
* InputStream in = uart.getInputStream();
* OutputStream out = uart.getOutputStream();
* out.write(new String("Hello").getBytes());
* int i = in.read(); // blocking
* ...
* uart.close(); // free UART module and pins
* </pre>
*
* @see IOIO#openUart(DigitalInput.Spec, DigitalOutput.Spec, int, Uart.Parity,
* Uart.StopBits)
*/
public interface Uart extends Closeable {
/** Parity-bit mode. */
enum Parity {
/** No parity. */
NONE,
/** Even parity. */
EVEN,
/** Odd parity. */
ODD
}
/** Number of stop-bits. */
enum StopBits {
/** One stop bit. */
ONE,
/** Two stop bits. */
TWO
}
/**
* Gets the input stream.
*
* @return An input stream.
*/
public InputStream getInputStream();
/**
* Gets the output stream.
*
* @return An output stream.
*/
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;
import ioio.lib.api.IOIOConnection;
@@ -8,43 +37,41 @@ import java.io.InputStream;
import java.io.OutputStream;
import java.util.UUID;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothSocket;
import android.os.Build;
import android.util.Log;
public class BluetoothIOIOConnection implements IOIOConnection {
private static final String TAG = "BluetoothIOIOConnection";
private BluetoothSocket socket_ = null;
private boolean disconnect_ = false;
private final BluetoothDevice device_;
private final String name_;
private final String address_;
public BluetoothIOIOConnection(String name, String address) {
name_ = name;
address_ = address;
public BluetoothIOIOConnection(BluetoothDevice device) {
device_ = device;
name_ = device.getName();
address_ = device.getAddress();
}
@Override
public void waitForConnect() throws ConnectionLostException {
final BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
final BluetoothDevice ioioDevice = adapter.getRemoteDevice(address_);
synchronized (this) {
if (disconnect_) {
throw new ConnectionLostException();
}
Log.v(TAG, name_ + " Creating socket");
try {
socket_ = createSocket(ioioDevice);
socket_ = createSocket(device_);
} catch (IOException e) {
throw new ConnectionLostException(e);
}
Log.v(TAG, name_ + " Created socket");
}
// keep trying to connect as long as we're not aborting
while (true) {
try {
Log.v(TAG, name_ + "Connecting");
Log.v(TAG, "Attempting to connect to Bluetooth device: " + name_);
socket_.connect();
Log.v(TAG, "Established connection to device " + name_
+ " 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 {
try {
// We're trying to create an insecure socket, which is
// only supported
// in API 10 and up. If we fail, we try a secure socket
// with is in API
// 7 and up.
if (Build.VERSION.SDK_INT >= 10 ) {
// We're trying to create an insecure socket, which is only
// supported in API 10 and up. Otherwise, we try a secure socket
// which is in API 7 and up.
return device.createInsecureRfcommSocketToServiceRecord(UUID
.fromString("00001101-0000-1000-8000-00805F9B34FB"));
} catch (NoSuchMethodError e) {
} else {
return device.createRfcommSocketToServiceRecord(UUID
.fromString("00001101-0000-1000-8000-00805F9B34FB"));
}
@@ -82,7 +107,7 @@ public class BluetoothIOIOConnection implements IOIOConnection {
if (disconnect_) {
return;
}
Log.d(TAG, "Client initiated disconnect");
Log.v(TAG, "Client initiated disconnect");
disconnect_ = true;
if (socket_ != null) {
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;
public abstract class AbstractPin extends AbstractResource {
abstract class AbstractPin extends AbstractResource {
protected final int pinNum_;
AbstractPin(IOIOImpl ioio, int pinNum) throws ConnectionLostException {
@@ -38,6 +38,7 @@ public abstract class AbstractPin extends AbstractResource {
pinNum_ = pinNum;
}
@Override
synchronized public void close() {
super.close();
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.api.Closeable;
public class AbstractResource implements Closeable, DisconnectListener {
class AbstractResource implements Closeable, DisconnectListener {
enum State {
OPEN,
CLOSED,
@@ -53,6 +53,7 @@ public class AbstractResource implements Closeable, DisconnectListener {
}
}
@Override
synchronized public void close() {
if (state_ == State.CLOSED) {
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;
import java.io.IOException;
import ioio.lib.api.AnalogInput;
import ioio.lib.api.exception.ConnectionLostException;
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 boolean valid_ = false;
short[] buffer_;
int bufferSize_;
int bufferCapacity_;
int bufferReadCursor_;
int bufferWriteCursor_;
int bufferOverflowCount_ = 0;
AnalogInputImpl(IOIOImpl ioio, int pin) throws ConnectionLostException {
super(ioio, pin);
}
@Override
public float getVoltage() throws InterruptedException, ConnectionLostException {
public float getVoltage() throws InterruptedException,
ConnectionLostException {
return read() * getReference();
}
@@ -55,18 +64,20 @@ public class AnalogInputImpl extends AbstractPin implements AnalogInput, InputPi
@Override
synchronized public void setValue(int value) {
// Log.v("AnalogInputImpl", "Pin " + pinNum_ + " value is " + value);
assert(value >= 0 || value < 1024);
value_ = value;
assert (value >= 0 && value < 1024);
value_ = value;
if (!valid_) {
valid_ = true;
notifyAll();
}
bufferPush((short) value);
}
@Override
synchronized public float read() throws InterruptedException, ConnectionLostException {
synchronized public float read() throws InterruptedException,
ConnectionLostException {
checkState();
while (!valid_ && state_ != State.DISCONNECTED) {
while (!valid_ && state_ == State.OPEN) {
wait();
}
checkState();
@@ -87,4 +98,82 @@ public class AnalogInputImpl extends AbstractPin implements AnalogInput, InputPi
} 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.
*
*
* 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;
class Constants {
static final int NUM_PINS = 49;
static final int NUM_ANALOG_PINS = 16;
static final int NUM_PWM_MODULES = 9;
static final int NUM_UART_MODULES = 4;
static final int NUM_SPI_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_SINGLE = new int[] { 6, 7, 8};
static final int BUFFER_SIZE = 1024;
static final int PACKET_BUFFER_SIZE = 256;
static final int[][] TWI_PINS = new int[][] {{ 4, 5 }, { 47, 48 }, { 26, 25 }};
static final int[] ICSP_PINS = new int[] { 36, 37, 38 };
}
/*
* 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;
class Constants {
static final int NUM_PINS = 49;
static final int NUM_ANALOG_PINS = 16;
static final int NUM_PWM_MODULES = 9;
static final int NUM_UART_MODULES = 4;
static final int NUM_SPI_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_SINGLE = new int[] { 6, 7, 8};
static final int BUFFER_SIZE = 1024;
static final int PACKET_BUFFER_SIZE = 256;
static final int[][] TWI_PINS = new int[][] {{ 4, 5 }, { 47, 48 }, { 26, 25 }};
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;
public class DigitalInputImpl extends AbstractPin implements DigitalInput,
class DigitalInputImpl extends AbstractPin implements DigitalInput,
InputPinListener {
private boolean value_;
private boolean valid_ = false;
@@ -54,6 +54,7 @@ public class DigitalInputImpl extends AbstractPin implements DigitalInput,
notifyAll();
}
@Override
synchronized public void waitForValue(boolean value)
throws InterruptedException, ConnectionLostException {
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;
public class DigitalOutputImpl extends AbstractPin implements DigitalOutput {
DigitalOutputImpl(IOIOImpl ioio, int pin) throws ConnectionLostException {
class DigitalOutputImpl extends AbstractPin implements DigitalOutput {
boolean value_;
DigitalOutputImpl(IOIOImpl ioio, int pin, boolean startValue) throws ConnectionLostException {
super(ioio, pin);
value_ = startValue;
}
@Override
synchronized public void write(boolean val) throws ConnectionLostException {
checkState();
try {
ioio_.protocol_.setDigitalOutLevel(pinNum_, val);
} catch (IOException e) {
throw new ConnectionLostException(e);
if (val != value_) {
try {
ioio_.protocol_.setDigitalOutLevel(pinNum_, val);
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.BlockingQueue;
public class FlowControlledOutputStream extends OutputStream {
class FlowControlledOutputStream extends OutputStream {
interface Sender {
void send(byte[] data, int size);
}
@@ -91,15 +91,14 @@ public class FlowControlledOutputStream extends OutputStream {
@Override
synchronized public void close() {
if (closed_) {
return;
}
closed_ = true;
notifyAll();
thread_.interrupt();
}
synchronized public void kill() {
thread_.interrupt();
}
class FlushThread extends Thread {
@Override
public void run() {

View File

@@ -32,7 +32,7 @@ import java.io.IOException;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
public class FlowControlledPacketSender {
class FlowControlledPacketSender {
interface Packet {
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.Queue;
public class IcspMasterImpl extends AbstractResource implements IcspMaster,
class IcspMasterImpl extends AbstractResource implements IcspMaster,
DataModuleListener {
private Queue<Integer> resultQueue_ = new LinkedList<Integer>();
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.Queue;
public class IncapImpl extends AbstractPin implements DataModuleListener,
class IncapImpl extends AbstractPin implements DataModuleListener,
PulseInput {
private static final int MAX_QUEUE_LEN = 32;
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;
public class IncomingState implements IncomingHandler {
class IncomingState implements IncomingHandler {
enum ConnectionState {
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
*/
public class ModuleAllocator {
class ModuleAllocator {
private final Set<Integer> availableModuleIds_;
private final Set<Integer> allocatedModuleIds_;
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;
public class PinFunctionMap {
class PinFunctionMap {
private static final boolean[] PERIPHERAL_OUT = new boolean[] { true,
false, false, true, true, true, true, true, false, false, true,
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;
public class PwmImpl extends AbstractResource implements PwmOutput {
class PwmImpl extends AbstractResource implements PwmOutput {
private final int pwmNum_;
private final int pinNum_;
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;
public class QueueInputStream extends InputStream {
class QueueInputStream extends InputStream {
private enum State {
OPEN, CLOSED, KILLED
};
private final Queue<Byte> queue_ = new ArrayBlockingQueue<Byte>(
Constants.BUFFER_SIZE);
private boolean closed_ = false;
private State state_ = State.OPEN;
@Override
synchronized public int read() throws IOException {
try {
while (!closed_ && queue_.isEmpty()) {
while (state_ == State.OPEN && queue_.isEmpty()) {
wait();
}
if (closed_) {
if (state_ == State.KILLED) {
throw new IOException("Stream has been closed");
}
if (state_ == State.CLOSED && queue_.isEmpty()) {
return -1;
}
return ((int) queue_.remove()) & 0xFF;
} catch (InterruptedException e) {
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) {
for (int i = 0; i < size; ++i) {
if (queue_.size() == Constants.BUFFER_SIZE) {
@@ -73,7 +107,19 @@ public class QueueInputStream extends InputStream {
@Override
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;
public class SocketIOIOConnection implements IOIOConnection {
private static final String TAG = "SocketIOIOConnection";
private final int port_;
private ServerSocket server_ = null;
private Socket socket_ = null;
@@ -48,7 +49,7 @@ public class SocketIOIOConnection implements IOIOConnection {
private boolean server_owned_by_connect_ = true;
private boolean socket_owned_by_connect_ = true;
public SocketIOIOConnection(Integer port) {
public SocketIOIOConnection(int port) {
port_ = port;
}
@@ -59,13 +60,13 @@ public class SocketIOIOConnection implements IOIOConnection {
if (disconnect_) {
throw new ConnectionLostException();
}
Log.d("SocketIOIOConnection", "Creating server socket");
Log.v(TAG, "Creating server socket");
server_ = new ServerSocket(port_);
server_owned_by_connect_ = false;
}
Log.d("SocketIOIOConnection", "Waiting for TCP connection");
Log.v(TAG, "Waiting for TCP connection");
socket_ = server_.accept();
Log.d("SocketIOIOConnection", "TCP connected");
Log.v(TAG, "TCP connected");
synchronized (this) {
if (disconnect_) {
socket_.close();
@@ -80,18 +81,18 @@ public class SocketIOIOConnection implements IOIOConnection {
try {
server_.close();
} catch (IOException e1) {
Log.e("SocketIOIOConnection", "Unexpected exception", e1);
Log.e(TAG, "Unexpected exception", e1);
}
}
if (socket_owned_by_connect_ && socket_ != null) {
try {
socket_.close();
} catch (IOException e1) {
Log.e("SocketIOIOConnection", "Unexpected exception", e1);
Log.e(TAG, "Unexpected exception", e1);
}
}
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);
}
@@ -103,13 +104,13 @@ public class SocketIOIOConnection implements IOIOConnection {
if (disconnect_) {
return;
}
Log.d("SocketIOIOConnection", "Client initiated disconnect");
Log.v(TAG, "Client initiated disconnect");
disconnect_ = true;
if (!server_owned_by_connect_) {
try {
server_.close();
} catch (IOException e1) {
Log.e("SocketIOIOConnection", "Unexpected exception", e1);
Log.e(TAG, "Unexpected exception", e1);
}
}
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;
public class SpiMasterImpl extends AbstractResource implements SpiMaster,
class SpiMasterImpl extends AbstractResource implements SpiMaster,
DataModuleListener, Sender {
public class SpiResult implements Result {
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;
public class TwiMasterImpl extends AbstractResource implements TwiMaster,
class TwiMasterImpl extends AbstractResource implements TwiMaster,
DataModuleListener, Sender {
class TwiResult implements Result {
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;
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 final int uartNum_;
@@ -87,7 +87,8 @@ public class UartImpl extends AbstractResource implements DataModuleListener, Se
@Override
synchronized public void disconnected() {
super.disconnected();
outgoing_.kill();
incoming_.kill();
outgoing_.close();
}
@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;
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.util.IOIOConnectionDiscovery.IOIOConnectionSpec;
import java.util.Collection;
import java.util.LinkedList;
import android.app.Activity;
import android.os.Looper;
import android.util.Log;
/**
* A convenience class for easy creation of IOIO-based applications.
*
* It is used by creating a concrete 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.
*
* In the basic usage the client should extend this class and implement
* {@link #createIOIOThread()}, which should return an implementation of the
* {@link IOIOThread} abstract class. In this implementation, the client
* implements the {@link IOIOThread#setup()} method, which gets called as soon
* as communication with the IOIO is established, and the {@link IOIOThread
* #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.
*
* In addition, the {@link IOIOThread#disconnected()} method may be overridden
* in order to execute logic as soon as a disconnection occurs for whichever
* reason. The {@link IOIOThread#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.
*
* 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 #createIOIOThread(String, Object[])} instead of
* {@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 array will contain an
* {@link Integer} representing the local port number.
*
*/
public abstract class AbstractIOIOActivity extends Activity {
private static final String TAG = "AbstractIOIOActivity";
private IOIOConnectionSpec currentSpec_;
private Collection<IOIOThread> threads_ = new LinkedList<IOIOThread>();
/**
* Subclasses should call this method from their own onResume() if
* overloaded. It takes care of connecting with the IOIO.
*/
@Override
protected void onResume() {
super.onResume();
createAllThreads();
startAllThreads();
}
/**
* Subclasses should call this method from their own onPause() if
* overloaded. It takes care of disconnecting from the IOIO.
*/
@Override
protected void onPause() {
super.onPause();
abortAllThreads();
try {
joinAllThreads();
} catch (InterruptedException e) {
}
}
/**
* Subclasses should implement this method by returning a concrete subclass
* 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
* scenarios, where you want to identify which IOIO the thread is for,
* consider using {@link #createIOIOThread()} instead.
*
* @return An implementation of {@link IOIOThread}, or <code>null</code> to
* skip.
*/
protected IOIOThread createIOIOThread() {
return null;
}
/**
* Subclasses should implement this method by returning a concrete subclass
* of {@link IOIOThread}. This overload is useful in multi-IOIO scenarios,
* where you want to identify which IOIO the thread is for. The provided
* arguments should provide enough information to be unique per connection.
* <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
* wireless connection, any wired connection attempts may be rejected, thus
* saving resources used for listening for incoming wired connections.
*
* @param connectionClass
* The fully-qualified name of the connection class used to
* connect to the IOIO.
* @param connectionArgs
* A list of arguments passed to the constructor of the
* 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.
*/
protected IOIOThread createIOIOThread(String connectionClass,
Object[] connectionArgs) {
return createIOIOThread();
}
/**
* An abstract class, which facilitates a thread dedicated for communication
* with a single physical IOIO device.
*/
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;
private final IOIOConnectionSpec spec_ = currentSpec_;
/**
* Subclasses should override this method for performing operations to
* be done once as soon as IOIO communication is established. Typically,
* this will include opening pins and modules using the openXXX()
* methods of the {@link #ioio_} field.
*/
protected void setup() 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.
*/
protected void loop() throws ConnectionLostException,
InterruptedException {
sleep(100000);
}
/**
* 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
* {@link #ioio_} member must not be used from within this method.
*/
protected void disconnected() throws InterruptedException {
}
/**
* Subclasses should override this method for performing operations to
* be done if an incompatible IOIO firmware is detected. The
* {@link #ioio_} member must not be used from within this method. This
* method will only be called once, until a compatible IOIO is connected
* (i.e. {@link #setup()} gets called).
*/
protected void incompatible() {
}
/** Not relevant to subclasses. */
@Override
public final void run() {
super.run();
Looper.prepare();
while (true) {
try {
synchronized (this) {
if (abort_) {
break;
}
ioio_ = IOIOFactory.create(spec_.className, spec_.args);
}
ioio_.waitForConnect();
connected_ = true;
setup();
while (!abort_) {
loop();
}
ioio_.disconnect();
} catch (ConnectionLostException e) {
if (abort_) {
break;
}
} catch (InterruptedException e) {
ioio_.disconnect();
break;
} catch (IncompatibilityException e) {
Log.e(TAG, "Incompatible IOIO firmware", e);
incompatible();
// nothing to do - just wait until physical disconnection
try {
ioio_.waitForDisconnect();
} catch (InterruptedException e1) {
ioio_.disconnect();
}
} catch (Exception e) {
Log.e(TAG, "Unexpected exception caught", e);
ioio_.disconnect();
break;
} finally {
try {
if (ioio_ != null) {
ioio_.waitForDisconnect();
if (connected_) {
disconnected();
}
}
} catch (InterruptedException e) {
}
}
}
}
/** 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<IOIOConnectionSpec> specs = getConnectionSpecs();
for (IOIOConnectionSpec spec : specs) {
currentSpec_ = spec;
IOIOThread thread = createIOIOThread(spec.className, spec.args);
if (thread != null) {
threads_.add(thread);
}
}
}
private void startAllThreads() {
for (IOIOThread thread : threads_) {
thread.start();
}
}
private Collection<IOIOConnectionSpec> getConnectionSpecs() {
Collection<IOIOConnectionSpec> result = new LinkedList<IOIOConnectionSpec>();
addConnectionSpecs("ioio.lib.util.SocketIOIOConnectionDiscovery",
result);
addConnectionSpecs(
"ioio.lib.bluetooth.BluetoothIOIOConnectionDiscovery", result);
return result;
}
private void addConnectionSpecs(String discoveryClassName,
Collection<IOIOConnectionSpec> result) {
try {
Class<?> cls = Class.forName(discoveryClassName);
IOIOConnectionDiscovery discovery = (IOIOConnectionDiscovery) cls
.newInstance();
discovery.getSpecs(result);
} catch (ClassNotFoundException e) {
Log.d(TAG, "Discovery class not found: " + discoveryClassName
+ ". Not adding.");
} catch (Exception e) {
Log.w(TAG,
"Exception caught while discovering connections - not adding connections of class "
+ discoveryClassName, e);
}
}
}
/*
* 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.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 ioio.lib.util.android.ContextWrapperDependent;
import java.util.Collection;
import java.util.LinkedList;
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.util.Log;
/**
* A convenience class for easy creation of IOIO-based applications.
*
* It is used by creating a concrete 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.
*
* In the basic usage the client should extend this class and implement
* {@link #createIOIOThread()}, which should return an implementation of the
* {@link AbstractIOIOActivity.IOIOThread} abstract class. In this
* implementation, the client implements the
* {@link AbstractIOIOActivity.IOIOThread#setup()} method, which gets called as
* soon as communication with the IOIO is established, and the
* {@link AbstractIOIOActivity.IOIOThread#loop()} method, which gets called
* repetitively as long as the IOIO is connected. Both methods should access the
* {@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
* occurs for whichever reason. The
* {@link AbstractIOIOActivity.IOIOThread#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.
*
* 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 #createIOIOThread(String, Object)} instead of
* {@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
* contain an {@link Integer} representing the local port number.
*
* @deprecated Please use {@link ioio.lib.util.android.IOIOActivity} instead.
*/
public abstract class AbstractIOIOActivity extends Activity {
private static final String TAG = "AbstractIOIOActivity";
static {
IOIOConnectionRegistry
.addBootstraps(new String[] {
"ioio.lib.android.accessory.AccessoryConnectionBootstrap",
"ioio.lib.android.bluetooth.BluetoothIOIOConnectionBootstrap" });
}
private Collection<IOIOThread> threads_ = new LinkedList<IOIOThread>();
private Collection<IOIOConnectionBootstrap> bootstraps_ = IOIOConnectionRegistry
.getBootstraps();
private IOIOConnectionFactory currentConnectionFactory_;
/**
* 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);
for (IOIOConnectionBootstrap bootstrap : bootstraps_) {
if (bootstrap instanceof ContextWrapperDependent) {
((ContextWrapperDependent) bootstrap).onCreate(this);
}
}
}
/**
* Subclasses should call this method from their own onDestroy() if
* overloaded. It takes care of connecting with the IOIO.
*/
@Override
protected void onDestroy() {
for (IOIOConnectionBootstrap bootstrap : bootstraps_) {
if (bootstrap instanceof ContextWrapperDependent) {
((ContextWrapperDependent) bootstrap).onDestroy();
}
}
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();
for (IOIOConnectionBootstrap bootstrap : bootstraps_) {
if (bootstrap instanceof ContextWrapperDependent) {
((ContextWrapperDependent) bootstrap).open();
}
}
createAllThreads();
startAllThreads();
}
/**
* Subclasses should call this method from their own onStop() if overloaded.
* It takes care of disconnecting from the IOIO.
*/
@Override
protected void onStop() {
abortAllThreads();
try {
joinAllThreads();
} catch (InterruptedException e) {
}
for (IOIOConnectionBootstrap bootstrap : bootstraps_) {
if (bootstrap instanceof ContextWrapperDependent) {
((ContextWrapperDependent) bootstrap).close();
}
}
super.onStop();
}
@Override
protected void onNewIntent(Intent intent) {
super.onNewIntent(intent);
if ((intent.getFlags() & Intent.FLAG_ACTIVITY_NEW_TASK) != 0) {
for (IOIOConnectionBootstrap bootstrap : bootstraps_) {
if (bootstrap instanceof ContextWrapperDependent) {
((ContextWrapperDependent) bootstrap).open();
}
}
}
}
/**
* Subclasses must either implement this method or its other overload by
* returning a concrete subclass of {@link IOIOThread}. <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 using {@link #createIOIOThread()} instead.
*
* @return An implementation of {@link IOIOThread}, or <code>null</code> to
* skip.
*/
protected IOIOThread createIOIOThread() {
throw new RuntimeException(
"Client must override on of the createIOIOThread overloads!");
}
/**
* Subclasses should implement this method by returning a concrete subclass
* of {@link IOIOThread}. This overload is useful in multi-IOIO scenarios,
* where you want to identify which IOIO the thread is for. The provided
* arguments should provide enough information to be unique per connection.
* <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
* 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 IOIOThread}, or <code>null</code> to
* skip.
*/
protected IOIOThread createIOIOThread(String connectionType, Object extra) {
return createIOIOThread();
}
/**
* An abstract class, which facilitates a thread dedicated for communication
* with a single physical IOIO device.
*/
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;
private final IOIOConnectionFactory connectionFactory_ = currentConnectionFactory_;
/**
* Subclasses should override this method for performing operations to
* be done once as soon as IOIO communication is established. Typically,
* this will include opening pins and modules using the openXXX()
* methods of the {@link #ioio_} field.
*/
protected void setup() 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.
*/
protected void loop() throws ConnectionLostException,
InterruptedException {
sleep(100000);
}
/**
* 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
* {@link #ioio_} member must not be used from within this method. This
* method should not block for long, since it may cause an ANR.
*/
protected void disconnected() {
}
/**
* Subclasses should override this method for performing operations to
* be done if an incompatible IOIO firmware is detected. The
* {@link #ioio_} member must not be used from within this method. This
* method will only be called once, until a compatible IOIO is connected
* (i.e. {@link #setup()} gets called).
*/
protected void incompatible() {
}
/** Not relevant to subclasses. */
@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;
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();
}
}