diff --git a/IOIOLib/.classpath b/IOIOLib/.classpath index a4763d1..3f9691c 100755 --- a/IOIOLib/.classpath +++ b/IOIOLib/.classpath @@ -1,8 +1,8 @@ - - + + diff --git a/IOIOLib/bin/classes/ioio/lib/bluetooth/BluetoothIOIOConnection.class b/IOIOLib/bin/classes/ioio/lib/bluetooth/BluetoothIOIOConnection.class index d78a3d2..558fdf7 100644 Binary files a/IOIOLib/bin/classes/ioio/lib/bluetooth/BluetoothIOIOConnection.class and b/IOIOLib/bin/classes/ioio/lib/bluetooth/BluetoothIOIOConnection.class differ diff --git a/IOIOLib/bin/classes/ioio/lib/impl/AnalogInputImpl.class b/IOIOLib/bin/classes/ioio/lib/impl/AnalogInputImpl.class index 3f63933..fa4306a 100644 Binary files a/IOIOLib/bin/classes/ioio/lib/impl/AnalogInputImpl.class and b/IOIOLib/bin/classes/ioio/lib/impl/AnalogInputImpl.class differ diff --git a/IOIOLib/bin/classes/ioio/lib/impl/Constants.class b/IOIOLib/bin/classes/ioio/lib/impl/Constants.class index 1115ed1..f3b3595 100644 Binary files a/IOIOLib/bin/classes/ioio/lib/impl/Constants.class and b/IOIOLib/bin/classes/ioio/lib/impl/Constants.class differ diff --git a/IOIOLib/bin/classes/ioio/lib/impl/DigitalInputImpl.class b/IOIOLib/bin/classes/ioio/lib/impl/DigitalInputImpl.class index ca776c9..6cfc636 100644 Binary files a/IOIOLib/bin/classes/ioio/lib/impl/DigitalInputImpl.class and b/IOIOLib/bin/classes/ioio/lib/impl/DigitalInputImpl.class differ diff --git a/IOIOLib/bin/classes/ioio/lib/impl/DigitalOutputImpl.class b/IOIOLib/bin/classes/ioio/lib/impl/DigitalOutputImpl.class index 5d8c712..8377952 100644 Binary files a/IOIOLib/bin/classes/ioio/lib/impl/DigitalOutputImpl.class and b/IOIOLib/bin/classes/ioio/lib/impl/DigitalOutputImpl.class differ diff --git a/IOIOLib/bin/classes/ioio/lib/impl/FlowControlledOutputStream.class b/IOIOLib/bin/classes/ioio/lib/impl/FlowControlledOutputStream.class index c732183..e2f38f7 100644 Binary files a/IOIOLib/bin/classes/ioio/lib/impl/FlowControlledOutputStream.class and b/IOIOLib/bin/classes/ioio/lib/impl/FlowControlledOutputStream.class differ diff --git a/IOIOLib/bin/classes/ioio/lib/impl/FlowControlledPacketSender$FlushThread.class b/IOIOLib/bin/classes/ioio/lib/impl/FlowControlledPacketSender$FlushThread.class index 07e4ac8..2da7e64 100644 Binary files a/IOIOLib/bin/classes/ioio/lib/impl/FlowControlledPacketSender$FlushThread.class and b/IOIOLib/bin/classes/ioio/lib/impl/FlowControlledPacketSender$FlushThread.class differ diff --git a/IOIOLib/bin/classes/ioio/lib/impl/FlowControlledPacketSender.class b/IOIOLib/bin/classes/ioio/lib/impl/FlowControlledPacketSender.class index e72b01e..f4e1cca 100644 Binary files a/IOIOLib/bin/classes/ioio/lib/impl/FlowControlledPacketSender.class and b/IOIOLib/bin/classes/ioio/lib/impl/FlowControlledPacketSender.class differ diff --git a/IOIOLib/bin/classes/ioio/lib/impl/IOIOImpl.class b/IOIOLib/bin/classes/ioio/lib/impl/IOIOImpl.class index 7388142..31d158d 100644 Binary files a/IOIOLib/bin/classes/ioio/lib/impl/IOIOImpl.class and b/IOIOLib/bin/classes/ioio/lib/impl/IOIOImpl.class differ diff --git a/IOIOLib/bin/classes/ioio/lib/impl/IOIOProtocol$IncomingHandler.class b/IOIOLib/bin/classes/ioio/lib/impl/IOIOProtocol$IncomingHandler.class index 05b920c..d05e027 100644 Binary files a/IOIOLib/bin/classes/ioio/lib/impl/IOIOProtocol$IncomingHandler.class and b/IOIOLib/bin/classes/ioio/lib/impl/IOIOProtocol$IncomingHandler.class differ diff --git a/IOIOLib/bin/classes/ioio/lib/impl/IOIOProtocol$IncomingThread.class b/IOIOLib/bin/classes/ioio/lib/impl/IOIOProtocol$IncomingThread.class index 3233d4f..9151c99 100644 Binary files a/IOIOLib/bin/classes/ioio/lib/impl/IOIOProtocol$IncomingThread.class and b/IOIOLib/bin/classes/ioio/lib/impl/IOIOProtocol$IncomingThread.class differ diff --git a/IOIOLib/bin/classes/ioio/lib/impl/IOIOProtocol$PwmScale.class b/IOIOLib/bin/classes/ioio/lib/impl/IOIOProtocol$PwmScale.class index 5a0471b..68729c1 100644 Binary files a/IOIOLib/bin/classes/ioio/lib/impl/IOIOProtocol$PwmScale.class and b/IOIOLib/bin/classes/ioio/lib/impl/IOIOProtocol$PwmScale.class differ diff --git a/IOIOLib/bin/classes/ioio/lib/impl/IOIOProtocol.class b/IOIOLib/bin/classes/ioio/lib/impl/IOIOProtocol.class index 418da08..9f79375 100644 Binary files a/IOIOLib/bin/classes/ioio/lib/impl/IOIOProtocol.class and b/IOIOLib/bin/classes/ioio/lib/impl/IOIOProtocol.class differ diff --git a/IOIOLib/bin/classes/ioio/lib/impl/IcspMasterImpl.class b/IOIOLib/bin/classes/ioio/lib/impl/IcspMasterImpl.class index 5434699..bf94641 100644 Binary files a/IOIOLib/bin/classes/ioio/lib/impl/IcspMasterImpl.class and b/IOIOLib/bin/classes/ioio/lib/impl/IcspMasterImpl.class differ diff --git a/IOIOLib/bin/classes/ioio/lib/impl/IncomingState$ConnectionState.class b/IOIOLib/bin/classes/ioio/lib/impl/IncomingState$ConnectionState.class index 9cfeb3f..84230af 100644 Binary files a/IOIOLib/bin/classes/ioio/lib/impl/IncomingState$ConnectionState.class and b/IOIOLib/bin/classes/ioio/lib/impl/IncomingState$ConnectionState.class differ diff --git a/IOIOLib/bin/classes/ioio/lib/impl/IncomingState$DataModuleState.class b/IOIOLib/bin/classes/ioio/lib/impl/IncomingState$DataModuleState.class index ae1eb75..080422f 100644 Binary files a/IOIOLib/bin/classes/ioio/lib/impl/IncomingState$DataModuleState.class and b/IOIOLib/bin/classes/ioio/lib/impl/IncomingState$DataModuleState.class differ diff --git a/IOIOLib/bin/classes/ioio/lib/impl/IncomingState$InputPinState.class b/IOIOLib/bin/classes/ioio/lib/impl/IncomingState$InputPinState.class index 1a0c8d2..e909722 100644 Binary files a/IOIOLib/bin/classes/ioio/lib/impl/IncomingState$InputPinState.class and b/IOIOLib/bin/classes/ioio/lib/impl/IncomingState$InputPinState.class differ diff --git a/IOIOLib/bin/classes/ioio/lib/impl/IncomingState.class b/IOIOLib/bin/classes/ioio/lib/impl/IncomingState.class index cf806a1..a4e5aab 100644 Binary files a/IOIOLib/bin/classes/ioio/lib/impl/IncomingState.class and b/IOIOLib/bin/classes/ioio/lib/impl/IncomingState.class differ diff --git a/IOIOLib/bin/classes/ioio/lib/impl/PinFunctionMap.class b/IOIOLib/bin/classes/ioio/lib/impl/PinFunctionMap.class index f848507..3af9e48 100644 Binary files a/IOIOLib/bin/classes/ioio/lib/impl/PinFunctionMap.class and b/IOIOLib/bin/classes/ioio/lib/impl/PinFunctionMap.class differ diff --git a/IOIOLib/bin/classes/ioio/lib/impl/PwmImpl.class b/IOIOLib/bin/classes/ioio/lib/impl/PwmImpl.class index 604ccd3..de15eb4 100644 Binary files a/IOIOLib/bin/classes/ioio/lib/impl/PwmImpl.class and b/IOIOLib/bin/classes/ioio/lib/impl/PwmImpl.class differ diff --git a/IOIOLib/bin/classes/ioio/lib/impl/SocketIOIOConnection.class b/IOIOLib/bin/classes/ioio/lib/impl/SocketIOIOConnection.class index 0ff0680..f2b8417 100644 Binary files a/IOIOLib/bin/classes/ioio/lib/impl/SocketIOIOConnection.class and b/IOIOLib/bin/classes/ioio/lib/impl/SocketIOIOConnection.class differ diff --git a/IOIOLib/bin/classes/ioio/lib/impl/SpiMasterImpl.class b/IOIOLib/bin/classes/ioio/lib/impl/SpiMasterImpl.class index 73d8977..8cfa80f 100644 Binary files a/IOIOLib/bin/classes/ioio/lib/impl/SpiMasterImpl.class and b/IOIOLib/bin/classes/ioio/lib/impl/SpiMasterImpl.class differ diff --git a/IOIOLib/bin/classes/ioio/lib/impl/TwiMasterImpl.class b/IOIOLib/bin/classes/ioio/lib/impl/TwiMasterImpl.class index 47c7a4a..4a84fb4 100644 Binary files a/IOIOLib/bin/classes/ioio/lib/impl/TwiMasterImpl.class and b/IOIOLib/bin/classes/ioio/lib/impl/TwiMasterImpl.class differ diff --git a/IOIOLib/bin/classes/ioio/lib/impl/UartImpl.class b/IOIOLib/bin/classes/ioio/lib/impl/UartImpl.class index b210d3c..1be0403 100644 Binary files a/IOIOLib/bin/classes/ioio/lib/impl/UartImpl.class and b/IOIOLib/bin/classes/ioio/lib/impl/UartImpl.class differ diff --git a/IOIOLib/bin/classes/ioio/lib/util/AbstractIOIOActivity$IOIOThread.class b/IOIOLib/bin/classes/ioio/lib/util/AbstractIOIOActivity$IOIOThread.class index 8c1116b..bfcf152 100644 Binary files a/IOIOLib/bin/classes/ioio/lib/util/AbstractIOIOActivity$IOIOThread.class and b/IOIOLib/bin/classes/ioio/lib/util/AbstractIOIOActivity$IOIOThread.class differ diff --git a/IOIOLib/bin/classes/ioio/lib/util/AbstractIOIOActivity.class b/IOIOLib/bin/classes/ioio/lib/util/AbstractIOIOActivity.class index 5c9ac82..a3fb0be 100644 Binary files a/IOIOLib/bin/classes/ioio/lib/util/AbstractIOIOActivity.class and b/IOIOLib/bin/classes/ioio/lib/util/AbstractIOIOActivity.class differ diff --git a/IOIOLib/project.properties b/IOIOLib/project.properties index f28bc83..0e58ae1 100644 --- a/IOIOLib/project.properties +++ b/IOIOLib/project.properties @@ -9,4 +9,4 @@ android.library=true # Project target. -target=android-15 +target=android-17 diff --git a/IOIOLib/src/ioio/lib/api/DigitalInput.java b/IOIOLib/src/ioio/lib/api/DigitalInput.java index f773d88..76d58c8 100644 --- a/IOIOLib/src/ioio/lib/api/DigitalInput.java +++ b/IOIOLib/src/ioio/lib/api/DigitalInput.java @@ -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. - *

- * A digital input pin can be used to read logic-level signals. DigitalInput - * instances are obtained by calling {@link IOIO#openDigitalInput(DigitalInput.Spec)}. - *

- * 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)}. - *

- * 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. - *

- * Typical usage: - * - *

- * 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.
- * 
- */ -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. + *

+ * A digital input pin can be used to read logic-level signals. DigitalInput + * instances are obtained by calling {@link IOIO#openDigitalInput(DigitalInput.Spec)}. + *

+ * 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)}. + *

+ * 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. + *

+ * Typical usage: + * + *

+ * 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.
+ * 
+ */ +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; +} diff --git a/IOIOLib/src/ioio/lib/api/DigitalOutput.java b/IOIOLib/src/ioio/lib/api/DigitalOutput.java index 6d6a2a5..ccb8824 100644 --- a/IOIOLib/src/ioio/lib/api/DigitalOutput.java +++ b/IOIOLib/src/ioio/lib/api/DigitalOutput.java @@ -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. - *

- * A digital input pin can be used to generate logic-level signals. - * DigitalOutput instances are obtained by calling - * {@link IOIO#openDigitalOutput(DigitalOutput.Spec, boolean)}. - *

- * The value of the pin is set by calling {@link #write(boolean)}. - *

- * 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. - *

- * Typical usage: - * - *

- * 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.
- * 
- */ -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; -} +/* + * 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. + *

+ * A digital input pin can be used to generate logic-level signals. + * DigitalOutput instances are obtained by calling + * {@link IOIO#openDigitalOutput(DigitalOutput.Spec, boolean)}. + *

+ * The value of the pin is set by calling {@link #write(boolean)}. + *

+ * 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. + *

+ * Typical usage: + * + *

+ * 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.
+ * 
+ */ +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; +} diff --git a/IOIOLib/src/ioio/lib/api/IOIO.java b/IOIOLib/src/ioio/lib/api/IOIO.java index 627e2e7..2f2de6c 100644 --- a/IOIOLib/src/ioio/lib/api/IOIO.java +++ b/IOIOLib/src/ioio/lib/api/IOIO.java @@ -1,696 +1,696 @@ -/* - * 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.PulseInput.PulseMode; -import ioio.lib.api.TwiMaster.Rate; -import ioio.lib.api.Uart.Parity; -import ioio.lib.api.Uart.StopBits; -import ioio.lib.api.exception.ConnectionLostException; -import ioio.lib.api.exception.IncompatibilityException; -import ioio.lib.api.exception.OutOfResourceException; - -import java.io.Closeable; - -/** - * This interface provides control over all the IOIO board functions. - *

- * An instance of this interface is typically obtained by using the - * {@link IOIOFactory} class. Initially, a connection should be established, by - * calling {@link #waitForConnect()}. This method will block until the board is - * connected an a connection has been established. - *

- * During the connection process, this library verifies that the IOIO firmware - * is compatible with the required version. If not, {@link #waitForConnect()} - * will throw a {@link IncompatibilityException}, putting the {@link IOIO} - * instance in a "zombie" state: nothing could be done with it except calling - * {@link #disconnect()}, or waiting for the physical connection to drop via - * {@link #waitForDisconnect()}. - *

- * As soon as a connection is established, the IOIO can be used, typically, by - * calling the openXXX() functions to obtain additional interfaces for - * controlling specific function of the board. - *

- * Whenever a connection is lost as a result of physically disconnecting the - * board or as a result of calling {@link #disconnect()}, this instance and all - * the interfaces obtained from it become invalid, and will throw a - * {@link ConnectionLostException} on every operation. Once the connection is - * lost, those instances cannot be recycled, but rather it is required to create - * new ones and wait for a connection again. - *

- * Initially all pins are tri-stated (floating), and all functions are disabled. - * Whenever a connection is lost or dropped, the board will immediately return - * to the this initial state. - *

- * Typical usage: - * - *

- * IOIO ioio = IOIOFactory.create();
- * try {
- *   ioio.waitForConnect();
- *   DigitalOutput out = ioio.openDigitalOutput(10);
- *   out.write(true);
- *   ...
- * } catch (ConnectionLostException e) {
- * } catch (Exception e) {
- *   ioio.disconnect();
- * } finally {
- *   ioio.waitForDisconnect();
- * }
- * 
- * - * @see IOIOFactory#create() - */ -public interface IOIO { - /** An invalid pin number. */ - public static final int INVALID_PIN = -1; - /** The pin number used to designate the on-board 'stat' LED. */ - public static final int LED_PIN = 0; - - /** - * A versioned component in the system. - * - * @see IOIO#getImplVersion(VersionType) - */ - public enum VersionType { - /** Hardware version. */ - HARDWARE_VER, - /** Bootloader version. */ - BOOTLOADER_VER, - /** Application layer firmware version. */ - APP_FIRMWARE_VER, - /** IOIOLib version. */ - IOIOLIB_VER - } - - /** - * A state of a IOIO instance. - */ - public enum State { - /** Connection not yet established. */ - INIT, - /** Connected. */ - CONNECTED, - /** Connection established, incompatible firmware detected. */ - INCOMPATIBLE, - /** Disconnected. Instance is useless. */ - DEAD - } - - /** - * Establishes connection with the IOIO board. - *

- * This method is blocking until connection is established. This method can - * be aborted by calling {@link #disconnect()}. In this case, it will throw - * a {@link ConnectionLostException}. - * - * @throws ConnectionLostException - * An error occurred during connection or disconnect() has been - * called during connection. The instance state is disconnected. - * @throws IncompatibilityException - * An incompatible board firmware of hardware has been detected. - * The instance state is disconnected. - * @see #disconnect() - * @see #waitForDisconnect() - */ - public void waitForConnect() throws ConnectionLostException, - IncompatibilityException; - - /** - * Closes the connection to the board, or aborts a connection process - * started with waitForConnect(). - *

- * Once this method is called, this IOIO instance and all the instances - * obtain from it become invalid and will throw an exception on every - * operation. - *

- * This method is asynchronous, i.e. it returns immediately, but it is not - * guaranteed that all connection-related resources has already been freed - * and can be reused upon return. In cases when this is important, client - * can call {@link #waitForDisconnect()}, which will block until all - * resources have been freed. - */ - public void disconnect(); - - /** - * Blocks until IOIO has been disconnected and all connection-related - * resources have been freed, so that a new connection can be attempted. - * - * @throws InterruptedException - * When interrupt() has been called on this thread. This might - * mean that an immediate attempt to create and connect a new - * IOIO object might fail for resource contention. - * @see #disconnect() - * @see #waitForConnect() - */ - public void waitForDisconnect() throws InterruptedException; - - /** - * Gets the connections state. - * - * @return The connection state. - */ - public State getState(); - - /** - * Resets the entire state (returning to initial state), without dropping - * the connection. - *

- * It is equivalent to calling {@link Closeable#close()} on every interface - * obtained from this instance. A connection must have been established - * prior to calling this method, by invoking {@link #waitForConnect()}. - * - * @throws ConnectionLostException - * Connection was lost before or during the execution of this - * method. - * @see #hardReset() - */ - public void softReset() throws ConnectionLostException; - - /** - * Equivalent to disconnecting and reconnecting the board power supply. - *

- * The connection will be dropped and not reestablished. Full boot sequence - * will take place, so firmware upgrades can be performed. A connection must - * have been established prior to calling this method, by invoking - * {@link #waitForConnect()}. - * - * @throws ConnectionLostException - * Connection was lost before or during the execution of this - * method. - * @see #softReset() - */ - public void hardReset() throws ConnectionLostException; - - /** - * Query the implementation version of the system's components. The - * implementation version uniquely identifies a hardware revision or a - * software build. Returned version IDs are always 8-character long, - * according to the IOIO versioning system: first 4 characters are the - * version authority and last 4 characters are the revision. - * - * @param v - * The component whose version we query. - * @return An 8-character implementation version ID. - * @throws ConnectionLostException - * Connection was lost before or during the execution of this - * method. - */ - public String getImplVersion(VersionType v) throws ConnectionLostException; - - /** - * Open a pin for digital input. - *

- * A digital input pin can be used to read logic-level signals. The pin will - * operate in this mode until close() is invoked on the returned interface. - * It is illegal to open a pin that has already been opened and has not been - * closed. A connection must have been established prior to calling this - * method, by invoking {@link #waitForConnect()}. - * - * @param spec - * Pin specification, consisting of the pin number, as labeled on - * the board, and the mode, which determines whether the pin will - * be floating, pull-up or pull-down. See - * {@link DigitalInput.Spec.Mode} for more information. - * @return Interface of the assigned pin. - * @throws ConnectionLostException - * Connection was lost before or during the execution of this - * method. - * @see DigitalInput - */ - public DigitalInput openDigitalInput(DigitalInput.Spec spec) - throws ConnectionLostException; - - /** - * Shorthand for openDigitalInput(new DigitalInput.Spec(pin)). - * - * @see #openDigitalInput(ioio.lib.api.DigitalInput.Spec) - */ - public DigitalInput openDigitalInput(int pin) - throws ConnectionLostException; - - /** - * Shorthand for openDigitalInput(new DigitalInput.Spec(pin, mode)). - * - * @see #openDigitalInput(ioio.lib.api.DigitalInput.Spec) - */ - public DigitalInput openDigitalInput(int pin, DigitalInput.Spec.Mode mode) - throws ConnectionLostException; - - /** - * Open a pin for digital output. - *

- * A digital output pin can be used to generate logic-level signals. The pin - * will operate in this mode until close() is invoked on the returned - * interface. It is illegal to open a pin that has already been opened and - * has not been closed. A connection must have been established prior to - * calling this method, by invoking {@link #waitForConnect()}. - * - * @param spec - * Pin specification, consisting of the pin number, as labeled on - * the board, and the mode, which determines whether the pin will - * be normal or open-drain. See {@link DigitalOutput.Spec.Mode} - * for more information. - * @param startValue - * The initial logic level this pin will generate as soon at it - * is open. - * @return Interface of the assigned pin. - * @throws ConnectionLostException - * Connection was lost before or during the execution of this - * method. - * @see DigitalOutput - */ - public DigitalOutput openDigitalOutput(DigitalOutput.Spec spec, - boolean startValue) throws ConnectionLostException; - - /** - * Shorthand for openDigitalOutput(new DigitalOutput.Spec(pin, mode), - * startValue). - * - * @see #openDigitalOutput(ioio.lib.api.DigitalOutput.Spec, boolean) - */ - public DigitalOutput openDigitalOutput(int pin, - DigitalOutput.Spec.Mode mode, boolean startValue) - throws ConnectionLostException; - - /** - * Shorthand for openDigitalOutput(new DigitalOutput.Spec(pin), startValue). - * Pin mode will be "normal" (as opposed to "open-drain". - * - * @see #openDigitalOutput(ioio.lib.api.DigitalOutput.Spec, boolean) - */ - public DigitalOutput openDigitalOutput(int pin, boolean startValue) - throws ConnectionLostException; - - /** - * Shorthand for openDigitalOutput(new DigitalOutput.Spec(pin), false). Pin - * mode will be "normal" (as opposed to "open-drain". - * - * @see #openDigitalOutput(ioio.lib.api.DigitalOutput.Spec, boolean) - */ - public DigitalOutput openDigitalOutput(int pin) - throws ConnectionLostException; - - /** - * Open a pin for analog input. - *

- * An analog input pin can be used to measure voltage. Note that not every - * pin can be used as an analog input. See board documentation for the legal - * pins and permitted voltage range. - *

- * The pin will operate in this mode until close() is invoked on the - * returned interface. It is illegal to open a pin that has already been - * opened and has not been closed. A connection must have been established - * prior to calling this method, by invoking {@link #waitForConnect()}. - * - * @param pin - * Pin number, as labeled on the board. - * @return Interface of the assigned pin. - * @throws ConnectionLostException - * Connection was lost before or during the execution of this - * method. - * @see AnalogInput - */ - public AnalogInput openAnalogInput(int pin) throws ConnectionLostException; - - /** - * Open a pin for PWM (Pulse-Width Modulation) output. - *

- * A PWM pin produces a logic-level PWM signal. These signals are typically - * used for simulating analog outputs for controlling the intensity of LEDs, - * the rotation speed of motors, etc. They are also frequently used for - * controlling hobby servo motors. - *

- * Note that not every pin can be used as PWM output. In addition, the total - * number of concurrent PWM modules in use is limited. See board - * documentation for the legal pins and limit on concurrent usage. - *

- * The pin will operate in this mode until close() is invoked on the - * returned interface. It is illegal to open a pin that has already been - * opened and has not been closed. A connection must have been established - * prior to calling this method, by invoking {@link #waitForConnect()}. - * - * @param spec - * Pin specification, consisting of the pin number, as labeled on - * the board, and the mode, which determines whether the pin will - * be normal or open-drain. See {@link DigitalOutput.Spec.Mode} - * for more information. - * @param freqHz - * PWM frequency, in Hertz. - * @return Interface of the assigned pin. - * @throws ConnectionLostException - * Connection was lost before or during the execution of this - * method. - * @throws OutOfResourceException - * This is a runtime exception, so it is not necessary to catch - * it if the client guarantees that the total number of - * concurrent PWM resources is not exceeded. - * @see PwmOutput - */ - public PwmOutput openPwmOutput(DigitalOutput.Spec spec, int freqHz) - throws ConnectionLostException; - - /** - * Shorthand for openPwmOutput(new DigitalOutput.Spec(pin), freqHz). - * - * @see #openPwmOutput(ioio.lib.api.DigitalOutput.Spec, int) - */ - public PwmOutput openPwmOutput(int pin, int freqHz) - throws ConnectionLostException; - - /** - * Open a pin for pulse input. - *

- * The pulse input module is quite flexible. It enables several kinds of - * timing measurements on a digital signal: pulse width measurement - * (positive or negative pulse), and frequency of a periodic signal. - *

- * Note that not every pin can be used as pulse input. In addition, the - * total number of concurrent pulse input modules in use is limited. See - * board documentation for the legal pins and limit on concurrent usage. - *

- * The pin will operate in this mode until close() is invoked on the - * returned interface. It is illegal to open a pin that has already been - * opened and has not been closed. A connection must have been established - * prior to calling this method, by invoking {@link #waitForConnect()}. - * - * @param spec - * Pin specification, consisting of the pin number, as labeled on - * the board, and the mode, which determines whether the pin will - * be floating, pull-up or pull-down. See - * {@link DigitalInput.Spec.Mode} for more information. - * @param rate - * The clock rate to use for timing the signal. A faster clock - * rate will result in better precision but will only be able to - * measure narrow pulses / high frequencies. - * @param mode - * The mode in which to operate. Determines whether the module - * will measure pulse durations or frequency. - * @param doublePrecision - * Whether to open a double-precision pulse input module. Double- - * precision modules enable reading of much longer pulses and - * lower frequencies with high accuracy than single precision - * modules. However, their number is limited, so when possible, - * and if the resources are all needed, use single-precision. For - * more details on the exact spec of single- vs. double- - * precision, see {@link PulseInput}. - * @return An instance of the {@link PulseInput}, which can be used to - * obtain the data. - * @throws ConnectionLostException - * Connection was lost before or during the execution of this - * method. - * @throws OutOfResourceException - * This is a runtime exception, so it is not necessary to catch - * it if the client guarantees that the total number of - * concurrent PWM resources is not exceeded. - * @see PulseInput - */ - public PulseInput openPulseInput(DigitalInput.Spec spec, - PulseInput.ClockRate rate, PulseInput.PulseMode mode, - boolean doublePrecision) throws ConnectionLostException; - - /** - * Shorthand for openPulseInput(new DigitalInput.Spec(pin), rate, mode, - * true), i.e. opens a double-precision, 16MHz pulse input on the given pin - * with the given mode. - * - * @see #openPulseInput(ioio.lib.api.DigitalInput.Spec, - * ioio.lib.api.PulseInput.ClockRate, - * ioio.lib.api.PulseInput.PulseMode, boolean) - */ - public PulseInput openPulseInput(int pin, PulseMode mode) - throws ConnectionLostException; - - /** - * Open a UART module, enabling a bulk transfer of byte buffers. - *

- * 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. - *

- * Note that not every pin can be used for UART RX or TX. In addition, the - * total number of concurrent UART modules in use is limited. See board - * documentation for the legal pins and limit on concurrent usage. - *

- * The UART module will operate, and the pins will work in their respective - * modes until close() is invoked on the returned interface. It is illegal - * to use pins that have already been opened and has not been closed. A - * connection must have been established prior to calling this method, by - * invoking {@link #waitForConnect()}. - * - * @param rx - * Pin specification for the RX pin, consisting of the pin - * number, as labeled on the board, and the mode, which - * determines whether the pin will be floating, pull-up or - * pull-down. See {@link DigitalInput.Spec.Mode} for more - * information. null can be passed to designate that we do not - * want RX input to this module. - * @param tx - * Pin specification for the TX pin, consisting of the pin - * number, as labeled on the board, and the mode, which - * determines whether the pin will be normal or open-drain. See - * {@link DigitalOutput.Spec.Mode} for more information. null can - * be passed to designate that we do not want TX output to this - * module. - * @param baud - * The clock frequency of the UART module in Hz. - * @param parity - * The parity mode, as in {@link Parity}. - * @param stopbits - * Number of stop bits, as in {@link StopBits}. - * @return Interface of the assigned module. - * @throws ConnectionLostException - * Connection was lost before or during the execution of this - * method. - * @throws OutOfResourceException - * This is a runtime exception, so it is not necessary to catch - * it if the client guarantees that the total number of - * concurrent UART resources is not exceeded. - * @see Uart - */ - public Uart openUart(DigitalInput.Spec rx, DigitalOutput.Spec tx, int baud, - Parity parity, StopBits stopbits) throws ConnectionLostException; - - /** - * Shorthand for - * {@link #openUart(DigitalInput.Spec, DigitalOutput.Spec, int, Uart.Parity, Uart.StopBits)} - * , where the input pins use their default specs. {@link #INVALID_PIN} can - * be used on either pin if a TX- or RX-only UART is needed. - * - * @see #openUart(DigitalInput.Spec, DigitalOutput.Spec, int, Uart.Parity, - * Uart.StopBits) - */ - public Uart openUart(int rx, int tx, int baud, Parity parity, - StopBits stopbits) throws ConnectionLostException; - - /** - * Open a SPI master module, enabling communication with multiple - * SPI-enabled slave modules. - *

- * SPI is a common hardware communication protocol, enabling full-duplex, - * synchronous point-to-multi-point data transfer. It requires MOSI, MISO - * and CLK lines shared by all nodes, as well as a SS line per slave, - * connected 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. - *

- * Note that not every pin can be used for SPI MISO, MOSI or CLK. In - * addition, the total number of concurrent SPI modules in use is limited. - * See board documentation for the legal pins and limit on concurrent usage. - *

- * The SPI module will operate, and the pins will work in their respective - * modes until close() is invoked on the returned interface. It is illegal - * to use pins that have already been opened and has not been closed. A - * connection must have been established prior to calling this method, by - * invoking {@link #waitForConnect()}. - * - * @param miso - * Pin specification for the MISO (Master In Slave Out) pin, - * consisting of the pin number, as labeled on the board, and the - * mode, which determines whether the pin will be floating, - * pull-up or pull-down. See {@link DigitalInput.Spec.Mode} for - * more information. - * @param mosi - * Pin specification for the MOSI (Master Out Slave In) pin, - * consisting of the pin number, as labeled on the board, and the - * mode, which determines whether the pin will be normal or - * open-drain. See {@link DigitalOutput.Spec.Mode} for more - * information. - * @param clk - * Pin specification for the CLK pin, consisting of the pin - * number, as labeled on the board, and the mode, which - * determines whether the pin will be normal or open-drain. See - * {@link DigitalOutput.Spec.Mode} for more information. - * @param slaveSelect - * An array of pin specifications for each of the slaves' SS - * (Slave Select) pin. The index of this array designates the - * slave index, used later to refer to this slave. The spec is - * consisting of the pin number, as labeled on the board, and the - * mode, which determines whether the pin will be normal or - * open-drain. See {@link DigitalOutput.Spec.Mode} for more - * information. - * @param config - * The configuration of the SPI module. See - * {@link SpiMaster.Config} for details. - * @return Interface of the assigned module. - * @throws ConnectionLostException - * Connection was lost before or during the execution of this - * method. - * @throws OutOfResourceException - * This is a runtime exception, so it is not necessary to catch - * it if the client guarantees that the total number of - * concurrent SPI resources is not exceeded. - * @see SpiMaster - */ - public SpiMaster openSpiMaster(DigitalInput.Spec miso, - DigitalOutput.Spec mosi, DigitalOutput.Spec clk, - DigitalOutput.Spec[] slaveSelect, SpiMaster.Config config) - throws ConnectionLostException; - - /** - * Shorthand for - * {@link #openSpiMaster(ioio.lib.api.DigitalInput.Spec, ioio.lib.api.DigitalOutput.Spec, ioio.lib.api.DigitalOutput.Spec, ioio.lib.api.DigitalOutput.Spec[], ioio.lib.api.SpiMaster.Config)} - * , where the pins are all open with the default modes and default - * configuration values are used. - * - * @see #openSpiMaster(ioio.lib.api.DigitalInput.Spec, - * ioio.lib.api.DigitalOutput.Spec, ioio.lib.api.DigitalOutput.Spec, - * ioio.lib.api.DigitalOutput.Spec[], ioio.lib.api.SpiMaster.Config) - */ - public SpiMaster openSpiMaster(int miso, int mosi, int clk, - int[] slaveSelect, SpiMaster.Rate rate) - throws ConnectionLostException; - - /** - * Shorthand for - * {@link #openSpiMaster(ioio.lib.api.DigitalInput.Spec, ioio.lib.api.DigitalOutput.Spec, ioio.lib.api.DigitalOutput.Spec, ioio.lib.api.DigitalOutput.Spec[], ioio.lib.api.SpiMaster.Config)} - * , where the MISO pins is opened with pull up, and the other pins are open - * with the default modes and default configuration values are used. In this - * version, a single slave is used. - * - * @see #openSpiMaster(ioio.lib.api.DigitalInput.Spec, - * ioio.lib.api.DigitalOutput.Spec, ioio.lib.api.DigitalOutput.Spec, - * ioio.lib.api.DigitalOutput.Spec[], ioio.lib.api.SpiMaster.Config) - */ - public SpiMaster openSpiMaster(int miso, int mosi, int clk, - int slaveSelect, SpiMaster.Rate rate) - throws ConnectionLostException; - - /** - * Open a TWI (Two-Wire Interface, such as I2C/SMBus) master module, - * enabling communication with multiple TWI-enabled slave modules. - *

- * TWI is a common hardware communication protocol, enabling half-duplex, - * synchronous point-to-multi-point data transfer. It 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. - *

- * Note that there is a fixed number of TWI modules, and the pins they use - * are static. Client has to make sure these pins are not already opened - * before calling this method. See board documentation for the number of - * modules and the respective pins they use. - *

- * The TWI module will operate, and the pins will work in their respective - * modes until close() is invoked on the returned interface. It is illegal - * to use pins that have already been opened and has not been closed. A - * connection must have been established prior to calling this method, by - * invoking {@link #waitForConnect()}. - * - * @param twiNum - * The TWI module index to use. Will also determine the pins - * used. - * @param rate - * The clock rate. Can be 100KHz / 400KHz / 1MHz. - * @param smbus - * When true, will use SMBus voltage levels. When false, I2C - * voltage levels. - * @return Interface of the assigned module. - * @throws ConnectionLostException - * Connection was lost before or during the execution of this - * method. - * @see TwiMaster - */ - public TwiMaster openTwiMaster(int twiNum, Rate rate, boolean smbus) - throws ConnectionLostException; - - /** - * Open an ICSP channel, enabling Flash programming of an external PIC MCU, - * and in particular, another IOIO board. - *

- * ICSP (In-Circuit Serial Programming) is a protocol intended for - * programming of PIC MCUs. It is a serial protocol over three wires: PGC - * (clock), PGD (data) and MCLR (reset), where PGC and MCLR are controlled - * by the master and PGD is shared by the master and slave, depending on the - * transaction state. - *

- * Note that there is only one ICSP modules, and the pins it uses are - * static. Client has to make sure that the ICSP module is not already in - * use, as well as those dedicated pins. See board documentation for the - * actual pins used for ICSP. - * - * @return Interface of the ICSP module. - * @see IcspMaster - * @throws ConnectionLostException - * Connection was lost before or during the execution of this - * method. - */ - public IcspMaster openIcspMaster() throws ConnectionLostException; - - /** - * Start a batch of operations. This is strictly an optimization and will - * not change functionality: if the client knows that a sequence of several - * IOIO operations are going to be performed immediately following each - * other, a call to {@link #beginBatch()} before the sequence and - * {@link #endBatch()} after the sequence will cause the operations to be - * grouped into one transfer to the IOIO, thus reducing latency. A matching - * {@link #endBatch()} operation must always follow, or otherwise no - * operation will ever be actually executed. {@link #beginBatch()} / - * {@link #endBatch()} blocks may be nested - the transfer will occur when - * the outermost {@link #endBatch()} is invoked. Note that it is not - * guaranteed that no transfers will happen while inside a batch - it should - * be treated as a hint. Code running inside the block must be quick as it - * blocks all transfers to the IOIO, including those performed from - * other threads. - * - * @throws ConnectionLostException - * Connection was lost before or during the execution of this - * method. - */ - public void beginBatch() throws ConnectionLostException; - - /** - * End a batch of operations. For explanation, see {@link #beginBatch()}. - * - * @throws ConnectionLostException - * Connection was lost before or during the execution of this - * method. - */ - public void endBatch() 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.PulseInput.PulseMode; +import ioio.lib.api.TwiMaster.Rate; +import ioio.lib.api.Uart.Parity; +import ioio.lib.api.Uart.StopBits; +import ioio.lib.api.exception.ConnectionLostException; +import ioio.lib.api.exception.IncompatibilityException; +import ioio.lib.api.exception.OutOfResourceException; + +import java.io.Closeable; + +/** + * This interface provides control over all the IOIO board functions. + *

+ * An instance of this interface is typically obtained by using the + * {@link IOIOFactory} class. Initially, a connection should be established, by + * calling {@link #waitForConnect()}. This method will block until the board is + * connected an a connection has been established. + *

+ * During the connection process, this library verifies that the IOIO firmware + * is compatible with the required version. If not, {@link #waitForConnect()} + * will throw a {@link IncompatibilityException}, putting the {@link IOIO} + * instance in a "zombie" state: nothing could be done with it except calling + * {@link #disconnect()}, or waiting for the physical connection to drop via + * {@link #waitForDisconnect()}. + *

+ * As soon as a connection is established, the IOIO can be used, typically, by + * calling the openXXX() functions to obtain additional interfaces for + * controlling specific function of the board. + *

+ * Whenever a connection is lost as a result of physically disconnecting the + * board or as a result of calling {@link #disconnect()}, this instance and all + * the interfaces obtained from it become invalid, and will throw a + * {@link ConnectionLostException} on every operation. Once the connection is + * lost, those instances cannot be recycled, but rather it is required to create + * new ones and wait for a connection again. + *

+ * Initially all pins are tri-stated (floating), and all functions are disabled. + * Whenever a connection is lost or dropped, the board will immediately return + * to the this initial state. + *

+ * Typical usage: + * + *

+ * IOIO ioio = IOIOFactory.create();
+ * try {
+ *   ioio.waitForConnect();
+ *   DigitalOutput out = ioio.openDigitalOutput(10);
+ *   out.write(true);
+ *   ...
+ * } catch (ConnectionLostException e) {
+ * } catch (Exception e) {
+ *   ioio.disconnect();
+ * } finally {
+ *   ioio.waitForDisconnect();
+ * }
+ * 
+ * + * @see IOIOFactory#create() + */ +public interface IOIO { + /** An invalid pin number. */ + public static final int INVALID_PIN = -1; + /** The pin number used to designate the on-board 'stat' LED. */ + public static final int LED_PIN = 0; + + /** + * A versioned component in the system. + * + * @see IOIO#getImplVersion(VersionType) + */ + public enum VersionType { + /** Hardware version. */ + HARDWARE_VER, + /** Bootloader version. */ + BOOTLOADER_VER, + /** Application layer firmware version. */ + APP_FIRMWARE_VER, + /** IOIOLib version. */ + IOIOLIB_VER + } + + /** + * A state of a IOIO instance. + */ + public enum State { + /** Connection not yet established. */ + INIT, + /** Connected. */ + CONNECTED, + /** Connection established, incompatible firmware detected. */ + INCOMPATIBLE, + /** Disconnected. Instance is useless. */ + DEAD + } + + /** + * Establishes connection with the IOIO board. + *

+ * This method is blocking until connection is established. This method can + * be aborted by calling {@link #disconnect()}. In this case, it will throw + * a {@link ConnectionLostException}. + * + * @throws ConnectionLostException + * An error occurred during connection or disconnect() has been + * called during connection. The instance state is disconnected. + * @throws IncompatibilityException + * An incompatible board firmware of hardware has been detected. + * The instance state is disconnected. + * @see #disconnect() + * @see #waitForDisconnect() + */ + public void waitForConnect() throws ConnectionLostException, + IncompatibilityException; + + /** + * Closes the connection to the board, or aborts a connection process + * started with waitForConnect(). + *

+ * Once this method is called, this IOIO instance and all the instances + * obtain from it become invalid and will throw an exception on every + * operation. + *

+ * This method is asynchronous, i.e. it returns immediately, but it is not + * guaranteed that all connection-related resources has already been freed + * and can be reused upon return. In cases when this is important, client + * can call {@link #waitForDisconnect()}, which will block until all + * resources have been freed. + */ + public void disconnect(); + + /** + * Blocks until IOIO has been disconnected and all connection-related + * resources have been freed, so that a new connection can be attempted. + * + * @throws InterruptedException + * When interrupt() has been called on this thread. This might + * mean that an immediate attempt to create and connect a new + * IOIO object might fail for resource contention. + * @see #disconnect() + * @see #waitForConnect() + */ + public void waitForDisconnect() throws InterruptedException; + + /** + * Gets the connections state. + * + * @return The connection state. + */ + public State getState(); + + /** + * Resets the entire state (returning to initial state), without dropping + * the connection. + *

+ * It is equivalent to calling {@link Closeable#close()} on every interface + * obtained from this instance. A connection must have been established + * prior to calling this method, by invoking {@link #waitForConnect()}. + * + * @throws ConnectionLostException + * Connection was lost before or during the execution of this + * method. + * @see #hardReset() + */ + public void softReset() throws ConnectionLostException; + + /** + * Equivalent to disconnecting and reconnecting the board power supply. + *

+ * The connection will be dropped and not reestablished. Full boot sequence + * will take place, so firmware upgrades can be performed. A connection must + * have been established prior to calling this method, by invoking + * {@link #waitForConnect()}. + * + * @throws ConnectionLostException + * Connection was lost before or during the execution of this + * method. + * @see #softReset() + */ + public void hardReset() throws ConnectionLostException; + + /** + * Query the implementation version of the system's components. The + * implementation version uniquely identifies a hardware revision or a + * software build. Returned version IDs are always 8-character long, + * according to the IOIO versioning system: first 4 characters are the + * version authority and last 4 characters are the revision. + * + * @param v + * The component whose version we query. + * @return An 8-character implementation version ID. + * @throws ConnectionLostException + * Connection was lost before or during the execution of this + * method. + */ + public String getImplVersion(VersionType v) throws ConnectionLostException; + + /** + * Open a pin for digital input. + *

+ * A digital input pin can be used to read logic-level signals. The pin will + * operate in this mode until close() is invoked on the returned interface. + * It is illegal to open a pin that has already been opened and has not been + * closed. A connection must have been established prior to calling this + * method, by invoking {@link #waitForConnect()}. + * + * @param spec + * Pin specification, consisting of the pin number, as labeled on + * the board, and the mode, which determines whether the pin will + * be floating, pull-up or pull-down. See + * {@link DigitalInput.Spec.Mode} for more information. + * @return Interface of the assigned pin. + * @throws ConnectionLostException + * Connection was lost before or during the execution of this + * method. + * @see DigitalInput + */ + public DigitalInput openDigitalInput(DigitalInput.Spec spec) + throws ConnectionLostException; + + /** + * Shorthand for openDigitalInput(new DigitalInput.Spec(pin)). + * + * @see #openDigitalInput(ioio.lib.api.DigitalInput.Spec) + */ + public DigitalInput openDigitalInput(int pin) + throws ConnectionLostException; + + /** + * Shorthand for openDigitalInput(new DigitalInput.Spec(pin, mode)). + * + * @see #openDigitalInput(ioio.lib.api.DigitalInput.Spec) + */ + public DigitalInput openDigitalInput(int pin, DigitalInput.Spec.Mode mode) + throws ConnectionLostException; + + /** + * Open a pin for digital output. + *

+ * A digital output pin can be used to generate logic-level signals. The pin + * will operate in this mode until close() is invoked on the returned + * interface. It is illegal to open a pin that has already been opened and + * has not been closed. A connection must have been established prior to + * calling this method, by invoking {@link #waitForConnect()}. + * + * @param spec + * Pin specification, consisting of the pin number, as labeled on + * the board, and the mode, which determines whether the pin will + * be normal or open-drain. See {@link DigitalOutput.Spec.Mode} + * for more information. + * @param startValue + * The initial logic level this pin will generate as soon at it + * is open. + * @return Interface of the assigned pin. + * @throws ConnectionLostException + * Connection was lost before or during the execution of this + * method. + * @see DigitalOutput + */ + public DigitalOutput openDigitalOutput(DigitalOutput.Spec spec, + boolean startValue) throws ConnectionLostException; + + /** + * Shorthand for openDigitalOutput(new DigitalOutput.Spec(pin, mode), + * startValue). + * + * @see #openDigitalOutput(ioio.lib.api.DigitalOutput.Spec, boolean) + */ + public DigitalOutput openDigitalOutput(int pin, + DigitalOutput.Spec.Mode mode, boolean startValue) + throws ConnectionLostException; + + /** + * Shorthand for openDigitalOutput(new DigitalOutput.Spec(pin), startValue). + * Pin mode will be "normal" (as opposed to "open-drain". + * + * @see #openDigitalOutput(ioio.lib.api.DigitalOutput.Spec, boolean) + */ + public DigitalOutput openDigitalOutput(int pin, boolean startValue) + throws ConnectionLostException; + + /** + * Shorthand for openDigitalOutput(new DigitalOutput.Spec(pin), false). Pin + * mode will be "normal" (as opposed to "open-drain". + * + * @see #openDigitalOutput(ioio.lib.api.DigitalOutput.Spec, boolean) + */ + public DigitalOutput openDigitalOutput(int pin) + throws ConnectionLostException; + + /** + * Open a pin for analog input. + *

+ * An analog input pin can be used to measure voltage. Note that not every + * pin can be used as an analog input. See board documentation for the legal + * pins and permitted voltage range. + *

+ * The pin will operate in this mode until close() is invoked on the + * returned interface. It is illegal to open a pin that has already been + * opened and has not been closed. A connection must have been established + * prior to calling this method, by invoking {@link #waitForConnect()}. + * + * @param pin + * Pin number, as labeled on the board. + * @return Interface of the assigned pin. + * @throws ConnectionLostException + * Connection was lost before or during the execution of this + * method. + * @see AnalogInput + */ + public AnalogInput openAnalogInput(int pin) throws ConnectionLostException; + + /** + * Open a pin for PWM (Pulse-Width Modulation) output. + *

+ * A PWM pin produces a logic-level PWM signal. These signals are typically + * used for simulating analog outputs for controlling the intensity of LEDs, + * the rotation speed of motors, etc. They are also frequently used for + * controlling hobby servo motors. + *

+ * Note that not every pin can be used as PWM output. In addition, the total + * number of concurrent PWM modules in use is limited. See board + * documentation for the legal pins and limit on concurrent usage. + *

+ * The pin will operate in this mode until close() is invoked on the + * returned interface. It is illegal to open a pin that has already been + * opened and has not been closed. A connection must have been established + * prior to calling this method, by invoking {@link #waitForConnect()}. + * + * @param spec + * Pin specification, consisting of the pin number, as labeled on + * the board, and the mode, which determines whether the pin will + * be normal or open-drain. See {@link DigitalOutput.Spec.Mode} + * for more information. + * @param freqHz + * PWM frequency, in Hertz. + * @return Interface of the assigned pin. + * @throws ConnectionLostException + * Connection was lost before or during the execution of this + * method. + * @throws OutOfResourceException + * This is a runtime exception, so it is not necessary to catch + * it if the client guarantees that the total number of + * concurrent PWM resources is not exceeded. + * @see PwmOutput + */ + public PwmOutput openPwmOutput(DigitalOutput.Spec spec, int freqHz) + throws ConnectionLostException; + + /** + * Shorthand for openPwmOutput(new DigitalOutput.Spec(pin), freqHz). + * + * @see #openPwmOutput(ioio.lib.api.DigitalOutput.Spec, int) + */ + public PwmOutput openPwmOutput(int pin, int freqHz) + throws ConnectionLostException; + + /** + * Open a pin for pulse input. + *

+ * The pulse input module is quite flexible. It enables several kinds of + * timing measurements on a digital signal: pulse width measurement + * (positive or negative pulse), and frequency of a periodic signal. + *

+ * Note that not every pin can be used as pulse input. In addition, the + * total number of concurrent pulse input modules in use is limited. See + * board documentation for the legal pins and limit on concurrent usage. + *

+ * The pin will operate in this mode until close() is invoked on the + * returned interface. It is illegal to open a pin that has already been + * opened and has not been closed. A connection must have been established + * prior to calling this method, by invoking {@link #waitForConnect()}. + * + * @param spec + * Pin specification, consisting of the pin number, as labeled on + * the board, and the mode, which determines whether the pin will + * be floating, pull-up or pull-down. See + * {@link DigitalInput.Spec.Mode} for more information. + * @param rate + * The clock rate to use for timing the signal. A faster clock + * rate will result in better precision but will only be able to + * measure narrow pulses / high frequencies. + * @param mode + * The mode in which to operate. Determines whether the module + * will measure pulse durations or frequency. + * @param doublePrecision + * Whether to open a double-precision pulse input module. Double- + * precision modules enable reading of much longer pulses and + * lower frequencies with high accuracy than single precision + * modules. However, their number is limited, so when possible, + * and if the resources are all needed, use single-precision. For + * more details on the exact spec of single- vs. double- + * precision, see {@link PulseInput}. + * @return An instance of the {@link PulseInput}, which can be used to + * obtain the data. + * @throws ConnectionLostException + * Connection was lost before or during the execution of this + * method. + * @throws OutOfResourceException + * This is a runtime exception, so it is not necessary to catch + * it if the client guarantees that the total number of + * concurrent PWM resources is not exceeded. + * @see PulseInput + */ + public PulseInput openPulseInput(DigitalInput.Spec spec, + PulseInput.ClockRate rate, PulseInput.PulseMode mode, + boolean doublePrecision) throws ConnectionLostException; + + /** + * Shorthand for openPulseInput(new DigitalInput.Spec(pin), rate, mode, + * true), i.e. opens a double-precision, 16MHz pulse input on the given pin + * with the given mode. + * + * @see #openPulseInput(ioio.lib.api.DigitalInput.Spec, + * ioio.lib.api.PulseInput.ClockRate, + * ioio.lib.api.PulseInput.PulseMode, boolean) + */ + public PulseInput openPulseInput(int pin, PulseMode mode) + throws ConnectionLostException; + + /** + * Open a UART module, enabling a bulk transfer of byte buffers. + *

+ * 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. + *

+ * Note that not every pin can be used for UART RX or TX. In addition, the + * total number of concurrent UART modules in use is limited. See board + * documentation for the legal pins and limit on concurrent usage. + *

+ * The UART module will operate, and the pins will work in their respective + * modes until close() is invoked on the returned interface. It is illegal + * to use pins that have already been opened and has not been closed. A + * connection must have been established prior to calling this method, by + * invoking {@link #waitForConnect()}. + * + * @param rx + * Pin specification for the RX pin, consisting of the pin + * number, as labeled on the board, and the mode, which + * determines whether the pin will be floating, pull-up or + * pull-down. See {@link DigitalInput.Spec.Mode} for more + * information. null can be passed to designate that we do not + * want RX input to this module. + * @param tx + * Pin specification for the TX pin, consisting of the pin + * number, as labeled on the board, and the mode, which + * determines whether the pin will be normal or open-drain. See + * {@link DigitalOutput.Spec.Mode} for more information. null can + * be passed to designate that we do not want TX output to this + * module. + * @param baud + * The clock frequency of the UART module in Hz. + * @param parity + * The parity mode, as in {@link Parity}. + * @param stopbits + * Number of stop bits, as in {@link StopBits}. + * @return Interface of the assigned module. + * @throws ConnectionLostException + * Connection was lost before or during the execution of this + * method. + * @throws OutOfResourceException + * This is a runtime exception, so it is not necessary to catch + * it if the client guarantees that the total number of + * concurrent UART resources is not exceeded. + * @see Uart + */ + public Uart openUart(DigitalInput.Spec rx, DigitalOutput.Spec tx, int baud, + Parity parity, StopBits stopbits) throws ConnectionLostException; + + /** + * Shorthand for + * {@link #openUart(DigitalInput.Spec, DigitalOutput.Spec, int, Uart.Parity, Uart.StopBits)} + * , where the input pins use their default specs. {@link #INVALID_PIN} can + * be used on either pin if a TX- or RX-only UART is needed. + * + * @see #openUart(DigitalInput.Spec, DigitalOutput.Spec, int, Uart.Parity, + * Uart.StopBits) + */ + public Uart openUart(int rx, int tx, int baud, Parity parity, + StopBits stopbits) throws ConnectionLostException; + + /** + * Open a SPI master module, enabling communication with multiple + * SPI-enabled slave modules. + *

+ * SPI is a common hardware communication protocol, enabling full-duplex, + * synchronous point-to-multi-point data transfer. It requires MOSI, MISO + * and CLK lines shared by all nodes, as well as a SS line per slave, + * connected 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. + *

+ * Note that not every pin can be used for SPI MISO, MOSI or CLK. In + * addition, the total number of concurrent SPI modules in use is limited. + * See board documentation for the legal pins and limit on concurrent usage. + *

+ * The SPI module will operate, and the pins will work in their respective + * modes until close() is invoked on the returned interface. It is illegal + * to use pins that have already been opened and has not been closed. A + * connection must have been established prior to calling this method, by + * invoking {@link #waitForConnect()}. + * + * @param miso + * Pin specification for the MISO (Master In Slave Out) pin, + * consisting of the pin number, as labeled on the board, and the + * mode, which determines whether the pin will be floating, + * pull-up or pull-down. See {@link DigitalInput.Spec.Mode} for + * more information. + * @param mosi + * Pin specification for the MOSI (Master Out Slave In) pin, + * consisting of the pin number, as labeled on the board, and the + * mode, which determines whether the pin will be normal or + * open-drain. See {@link DigitalOutput.Spec.Mode} for more + * information. + * @param clk + * Pin specification for the CLK pin, consisting of the pin + * number, as labeled on the board, and the mode, which + * determines whether the pin will be normal or open-drain. See + * {@link DigitalOutput.Spec.Mode} for more information. + * @param slaveSelect + * An array of pin specifications for each of the slaves' SS + * (Slave Select) pin. The index of this array designates the + * slave index, used later to refer to this slave. The spec is + * consisting of the pin number, as labeled on the board, and the + * mode, which determines whether the pin will be normal or + * open-drain. See {@link DigitalOutput.Spec.Mode} for more + * information. + * @param config + * The configuration of the SPI module. See + * {@link SpiMaster.Config} for details. + * @return Interface of the assigned module. + * @throws ConnectionLostException + * Connection was lost before or during the execution of this + * method. + * @throws OutOfResourceException + * This is a runtime exception, so it is not necessary to catch + * it if the client guarantees that the total number of + * concurrent SPI resources is not exceeded. + * @see SpiMaster + */ + public SpiMaster openSpiMaster(DigitalInput.Spec miso, + DigitalOutput.Spec mosi, DigitalOutput.Spec clk, + DigitalOutput.Spec[] slaveSelect, SpiMaster.Config config) + throws ConnectionLostException; + + /** + * Shorthand for + * {@link #openSpiMaster(ioio.lib.api.DigitalInput.Spec, ioio.lib.api.DigitalOutput.Spec, ioio.lib.api.DigitalOutput.Spec, ioio.lib.api.DigitalOutput.Spec[], ioio.lib.api.SpiMaster.Config)} + * , where the pins are all open with the default modes and default + * configuration values are used. + * + * @see #openSpiMaster(ioio.lib.api.DigitalInput.Spec, + * ioio.lib.api.DigitalOutput.Spec, ioio.lib.api.DigitalOutput.Spec, + * ioio.lib.api.DigitalOutput.Spec[], ioio.lib.api.SpiMaster.Config) + */ + public SpiMaster openSpiMaster(int miso, int mosi, int clk, + int[] slaveSelect, SpiMaster.Rate rate) + throws ConnectionLostException; + + /** + * Shorthand for + * {@link #openSpiMaster(ioio.lib.api.DigitalInput.Spec, ioio.lib.api.DigitalOutput.Spec, ioio.lib.api.DigitalOutput.Spec, ioio.lib.api.DigitalOutput.Spec[], ioio.lib.api.SpiMaster.Config)} + * , where the MISO pins is opened with pull up, and the other pins are open + * with the default modes and default configuration values are used. In this + * version, a single slave is used. + * + * @see #openSpiMaster(ioio.lib.api.DigitalInput.Spec, + * ioio.lib.api.DigitalOutput.Spec, ioio.lib.api.DigitalOutput.Spec, + * ioio.lib.api.DigitalOutput.Spec[], ioio.lib.api.SpiMaster.Config) + */ + public SpiMaster openSpiMaster(int miso, int mosi, int clk, + int slaveSelect, SpiMaster.Rate rate) + throws ConnectionLostException; + + /** + * Open a TWI (Two-Wire Interface, such as I2C/SMBus) master module, + * enabling communication with multiple TWI-enabled slave modules. + *

+ * TWI is a common hardware communication protocol, enabling half-duplex, + * synchronous point-to-multi-point data transfer. It 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. + *

+ * Note that there is a fixed number of TWI modules, and the pins they use + * are static. Client has to make sure these pins are not already opened + * before calling this method. See board documentation for the number of + * modules and the respective pins they use. + *

+ * The TWI module will operate, and the pins will work in their respective + * modes until close() is invoked on the returned interface. It is illegal + * to use pins that have already been opened and has not been closed. A + * connection must have been established prior to calling this method, by + * invoking {@link #waitForConnect()}. + * + * @param twiNum + * The TWI module index to use. Will also determine the pins + * used. + * @param rate + * The clock rate. Can be 100KHz / 400KHz / 1MHz. + * @param smbus + * When true, will use SMBus voltage levels. When false, I2C + * voltage levels. + * @return Interface of the assigned module. + * @throws ConnectionLostException + * Connection was lost before or during the execution of this + * method. + * @see TwiMaster + */ + public TwiMaster openTwiMaster(int twiNum, Rate rate, boolean smbus) + throws ConnectionLostException; + + /** + * Open an ICSP channel, enabling Flash programming of an external PIC MCU, + * and in particular, another IOIO board. + *

+ * ICSP (In-Circuit Serial Programming) is a protocol intended for + * programming of PIC MCUs. It is a serial protocol over three wires: PGC + * (clock), PGD (data) and MCLR (reset), where PGC and MCLR are controlled + * by the master and PGD is shared by the master and slave, depending on the + * transaction state. + *

+ * Note that there is only one ICSP modules, and the pins it uses are + * static. Client has to make sure that the ICSP module is not already in + * use, as well as those dedicated pins. See board documentation for the + * actual pins used for ICSP. + * + * @return Interface of the ICSP module. + * @see IcspMaster + * @throws ConnectionLostException + * Connection was lost before or during the execution of this + * method. + */ + public IcspMaster openIcspMaster() throws ConnectionLostException; + + /** + * Start a batch of operations. This is strictly an optimization and will + * not change functionality: if the client knows that a sequence of several + * IOIO operations are going to be performed immediately following each + * other, a call to {@link #beginBatch()} before the sequence and + * {@link #endBatch()} after the sequence will cause the operations to be + * grouped into one transfer to the IOIO, thus reducing latency. A matching + * {@link #endBatch()} operation must always follow, or otherwise no + * operation will ever be actually executed. {@link #beginBatch()} / + * {@link #endBatch()} blocks may be nested - the transfer will occur when + * the outermost {@link #endBatch()} is invoked. Note that it is not + * guaranteed that no transfers will happen while inside a batch - it should + * be treated as a hint. Code running inside the block must be quick as it + * blocks all transfers to the IOIO, including those performed from + * other threads. + * + * @throws ConnectionLostException + * Connection was lost before or during the execution of this + * method. + */ + public void beginBatch() throws ConnectionLostException; + + /** + * End a batch of operations. For explanation, see {@link #beginBatch()}. + * + * @throws ConnectionLostException + * Connection was lost before or during the execution of this + * method. + */ + public void endBatch() throws ConnectionLostException; +} diff --git a/IOIOLib/src/ioio/lib/api/Uart.java b/IOIOLib/src/ioio/lib/api/Uart.java index 30faa91..dd59f34 100644 --- a/IOIOLib/src/ioio/lib/api/Uart.java +++ b/IOIOLib/src/ioio/lib/api/Uart.java @@ -1,107 +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.exception.ConnectionLostException; - -import java.io.InputStream; -import java.io.OutputStream; - -/** - * An interface for controlling a UART module. - *

- * 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)}. - *

- * 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. - *

- * 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. - *

- * 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. - *

- * Typical usage: - * - *

- * 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
- * 
- * - * @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(); -} +/* + * 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. + *

+ * 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)}. + *

+ * 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. + *

+ * 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. + *

+ * 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. + *

+ * Typical usage: + * + *

+ * 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
+ * 
+ * + * @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(); +} diff --git a/IOIOLib/src/ioio/lib/impl/Constants.java b/IOIOLib/src/ioio/lib/impl/Constants.java index abfefb4..aa82221 100644 --- a/IOIOLib/src/ioio/lib/impl/Constants.java +++ b/IOIOLib/src/ioio/lib/impl/Constants.java @@ -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 }; +} diff --git a/IOIOLib/src/ioio/lib/impl/IOIOImpl.java b/IOIOLib/src/ioio/lib/impl/IOIOImpl.java index 8731ea0..088110e 100644 --- a/IOIOLib/src/ioio/lib/impl/IOIOImpl.java +++ b/IOIOLib/src/ioio/lib/impl/IOIOImpl.java @@ -1,700 +1,700 @@ -/* - * 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.AnalogInput; -import ioio.lib.api.DigitalInput; -import ioio.lib.api.DigitalInput.Spec; -import ioio.lib.api.DigitalInput.Spec.Mode; -import ioio.lib.api.DigitalOutput; -import ioio.lib.api.IOIO; -import ioio.lib.api.IOIOConnection; -import ioio.lib.api.IcspMaster; -import ioio.lib.api.PulseInput; -import ioio.lib.api.PulseInput.ClockRate; -import ioio.lib.api.PulseInput.PulseMode; -import ioio.lib.api.PwmOutput; -import ioio.lib.api.SpiMaster; -import ioio.lib.api.TwiMaster; -import ioio.lib.api.TwiMaster.Rate; -import ioio.lib.api.Uart; -import ioio.lib.api.exception.ConnectionLostException; -import ioio.lib.api.exception.IncompatibilityException; -import ioio.lib.impl.IOIOProtocol.PwmScale; -import ioio.lib.impl.IncomingState.DisconnectListener; - -import java.io.IOException; - -import android.util.Log; - -public class IOIOImpl implements IOIO, DisconnectListener { - private static final String TAG = "IOIOImpl"; - private boolean disconnect_ = false; - - private static final byte[] REQUIRED_INTERFACE_ID = new byte[] { 'I', 'O', - 'I', 'O', '0', '0', '0', '3' }; - - private final IOIOConnection connection_; - private final IncomingState incomingState_ = new IncomingState(); - private final boolean openPins_[] = new boolean[Constants.NUM_PINS]; - private final boolean openTwi_[] = new boolean[Constants.NUM_TWI_MODULES]; - private boolean openIcsp_ = false; - private final ModuleAllocator pwmAllocator_ = new ModuleAllocator( - Constants.NUM_PWM_MODULES, "PWM"); - private final ModuleAllocator uartAllocator_ = new ModuleAllocator( - Constants.NUM_UART_MODULES, "UART"); - private final ModuleAllocator spiAllocator_ = new ModuleAllocator( - Constants.NUM_SPI_MODULES, "SPI"); - private final ModuleAllocator incapAllocatorDouble_ = new ModuleAllocator( - Constants.INCAP_MODULES_DOUBLE, "INCAP_DOUBLE"); - private final ModuleAllocator incapAllocatorSingle_ = new ModuleAllocator( - Constants.INCAP_MODULES_SINGLE, "INCAP_SINGLE"); - IOIOProtocol protocol_; - private State state_ = State.INIT; - - public IOIOImpl(IOIOConnection con) { - connection_ = con; - } - - @Override - public void waitForConnect() throws ConnectionLostException, - IncompatibilityException { - if (state_ == State.CONNECTED) { - return; - } - if (state_ == State.DEAD) { - throw new ConnectionLostException(); - } - addDisconnectListener(this); - Log.d(TAG, "Waiting for IOIO connection"); - try { - try { - Log.v(TAG, "Waiting for underlying connection"); - connection_.waitForConnect(); - synchronized (this) { - if (disconnect_) { - throw new ConnectionLostException(); - } - protocol_ = new IOIOProtocol(connection_.getInputStream(), - connection_.getOutputStream(), incomingState_); - // Once this block exits, a disconnect will also involve - // softClose(). - } - } catch (ConnectionLostException e) { - incomingState_.handleConnectionLost(); - throw e; - } - Log.v(TAG, "Waiting for handshake"); - incomingState_.waitConnectionEstablished(); - Log.v(TAG, "Querying for required interface ID"); - checkInterfaceVersion(); - Log.v(TAG, "Required interface ID is supported"); - state_ = State.CONNECTED; - Log.i(TAG, "IOIO connection established"); - } catch (ConnectionLostException e) { - Log.d(TAG, "Connection lost / aborted"); - state_ = State.DEAD; - throw e; - } catch (InterruptedException e) { - Log.e(TAG, "Unexpected exception", e); - } - } - - @Override - public synchronized void disconnect() { - Log.d(TAG, "Client requested disconnect."); - if (disconnect_) { - return; - } - disconnect_ = true; - try { - if (protocol_ != null) { - protocol_.softClose(); - } - } catch (IOException e) { - Log.e(TAG, "Soft close failed", e); - } - connection_.disconnect(); - } - - @Override - public synchronized void disconnected() { - state_ = State.DEAD; - if (disconnect_) { - return; - } - Log.d(TAG, "Physical disconnect."); - disconnect_ = true; - // The IOIOConnection doesn't necessarily know about the disconnect - connection_.disconnect(); - } - - @Override - public void waitForDisconnect() throws InterruptedException { - incomingState_.waitDisconnect(); - } - - @Override - public State getState() { - return state_; - } - - private void checkInterfaceVersion() throws IncompatibilityException, - ConnectionLostException, InterruptedException { - try { - protocol_.checkInterface(REQUIRED_INTERFACE_ID); - } catch (IOException e) { - throw new ConnectionLostException(e); - } - if (!incomingState_.waitForInterfaceSupport()) { - state_ = State.INCOMPATIBLE; - Log.e(TAG, "Required interface ID is not supported"); - throw new IncompatibilityException( - "IOIO firmware does not support required firmware: " - + new String(REQUIRED_INTERFACE_ID)); - } - } - - synchronized void removeDisconnectListener(DisconnectListener listener) { - incomingState_.removeDisconnectListener(listener); - } - - synchronized void addDisconnectListener(DisconnectListener listener) - throws ConnectionLostException { - incomingState_.addDisconnectListener(listener); - } - - synchronized void closePin(int pin) { - try { - checkState(); - if (!openPins_[pin]) { - throw new IllegalStateException("Pin not open: " + pin); - } - protocol_.setPinDigitalIn(pin, DigitalInput.Spec.Mode.FLOATING); - openPins_[pin] = false; - } catch (IOException e) { - } catch (ConnectionLostException e) { - } - } - - synchronized void closePwm(int pwmNum) { - try { - checkState(); - pwmAllocator_.releaseModule(pwmNum); - protocol_.setPwmPeriod(pwmNum, 0, IOIOProtocol.PwmScale.SCALE_1X); - } catch (IOException e) { - } catch (ConnectionLostException e) { - } - } - - synchronized void closeUart(int uartNum) { - try { - checkState(); - uartAllocator_.releaseModule(uartNum); - protocol_.uartClose(uartNum); - } catch (IOException e) { - } catch (ConnectionLostException e) { - } - } - - synchronized void closeTwi(int twiNum) { - try { - checkState(); - if (!openTwi_[twiNum]) { - throw new IllegalStateException("TWI not open: " + twiNum); - } - openTwi_[twiNum] = false; - openPins_[Constants.TWI_PINS[twiNum][0]] = false; - openPins_[Constants.TWI_PINS[twiNum][1]] = false; - protocol_.i2cClose(twiNum); - } catch (IOException e) { - } catch (ConnectionLostException e) { - } - } - - synchronized void closeIcsp() { - try { - checkState(); - if (!openIcsp_) { - throw new IllegalStateException("ICSP not open"); - } - openIcsp_ = false; - openPins_[Constants.ICSP_PINS[0]] = false; - openPins_[Constants.ICSP_PINS[1]] = false; - protocol_.icspClose(); - } catch (ConnectionLostException e) { - } catch (IOException e) { - } - } - - synchronized void closeSpi(int spiNum) { - try { - checkState(); - spiAllocator_.releaseModule(spiNum); - protocol_.spiClose(spiNum); - } catch (IOException e) { - } catch (ConnectionLostException e) { - } - } - - synchronized void closeIncap(int incapNum, boolean doublePrecision) { - try { - checkState(); - if (doublePrecision) { - incapAllocatorDouble_.releaseModule(incapNum); - } else { - incapAllocatorSingle_.releaseModule(incapNum); - } - protocol_.incapClose(incapNum); - } catch (IOException e) { - } catch (ConnectionLostException e) { - } - } - - @Override - synchronized public void softReset() throws ConnectionLostException { - checkState(); - try { - protocol_.softReset(); - } catch (IOException e) { - throw new ConnectionLostException(e); - } - } - - @Override - synchronized public void hardReset() throws ConnectionLostException { - checkState(); - try { - protocol_.hardReset(); - } catch (IOException e) { - throw new ConnectionLostException(e); - } - } - - @Override - public String getImplVersion(VersionType v) throws ConnectionLostException { - if (state_ == State.INIT) { - throw new IllegalStateException( - "Connection has not yet been established"); - } - switch (v) { - case HARDWARE_VER: - return incomingState_.hardwareId_; - case BOOTLOADER_VER: - return incomingState_.bootloaderId_; - case APP_FIRMWARE_VER: - return incomingState_.firmwareId_; - case IOIOLIB_VER: - return "IOIO0322"; - } - return null; - } - - @Override - public DigitalInput openDigitalInput(int pin) - throws ConnectionLostException { - return openDigitalInput(new DigitalInput.Spec(pin)); - } - - @Override - public DigitalInput openDigitalInput(int pin, Mode mode) - throws ConnectionLostException { - return openDigitalInput(new DigitalInput.Spec(pin, mode)); - } - - @Override - synchronized public DigitalInput openDigitalInput(DigitalInput.Spec spec) - throws ConnectionLostException { - checkState(); - PinFunctionMap.checkValidPin(spec.pin); - checkPinFree(spec.pin); - DigitalInputImpl result = new DigitalInputImpl(this, spec.pin); - addDisconnectListener(result); - openPins_[spec.pin] = true; - incomingState_.addInputPinListener(spec.pin, result); - try { - protocol_.setPinDigitalIn(spec.pin, spec.mode); - protocol_.setChangeNotify(spec.pin, true); - } catch (IOException e) { - result.close(); - throw new ConnectionLostException(e); - } - return result; - } - - @Override - public DigitalOutput openDigitalOutput(int pin, - ioio.lib.api.DigitalOutput.Spec.Mode mode, boolean startValue) - throws ConnectionLostException { - return openDigitalOutput(new DigitalOutput.Spec(pin, mode), startValue); - } - - @Override - synchronized public DigitalOutput openDigitalOutput( - DigitalOutput.Spec spec, boolean startValue) - throws ConnectionLostException { - checkState(); - PinFunctionMap.checkValidPin(spec.pin); - checkPinFree(spec.pin); - DigitalOutputImpl result = new DigitalOutputImpl(this, spec.pin, startValue); - addDisconnectListener(result); - openPins_[spec.pin] = true; - try { - protocol_.setPinDigitalOut(spec.pin, startValue, spec.mode); - } catch (IOException e) { - result.close(); - throw new ConnectionLostException(e); - } - return result; - } - - @Override - public DigitalOutput openDigitalOutput(int pin, boolean startValue) - throws ConnectionLostException { - return openDigitalOutput(new DigitalOutput.Spec(pin), startValue); - } - - @Override - public DigitalOutput openDigitalOutput(int pin) - throws ConnectionLostException { - return openDigitalOutput(new DigitalOutput.Spec(pin), false); - } - - @Override - synchronized public AnalogInput openAnalogInput(int pin) - throws ConnectionLostException { - checkState(); - PinFunctionMap.checkSupportsAnalogInput(pin); - checkPinFree(pin); - AnalogInputImpl result = new AnalogInputImpl(this, pin); - addDisconnectListener(result); - openPins_[pin] = true; - incomingState_.addInputPinListener(pin, result); - try { - protocol_.setPinAnalogIn(pin); - protocol_.setAnalogInSampling(pin, true); - } catch (IOException e) { - result.close(); - throw new ConnectionLostException(e); - } - return result; - } - - @Override - public PwmOutput openPwmOutput(int pin, int freqHz) - throws ConnectionLostException { - return openPwmOutput(new DigitalOutput.Spec(pin), freqHz); - } - - @Override - synchronized public PwmOutput openPwmOutput(DigitalOutput.Spec spec, - int freqHz) throws ConnectionLostException { - checkState(); - PinFunctionMap.checkSupportsPeripheralOutput(spec.pin); - checkPinFree(spec.pin); - int pwmNum = pwmAllocator_.allocateModule(); - - int scale = 0; - float baseUs; - int period; - while (true) { - final int clk = 16000000 / IOIOProtocol.PwmScale.values()[scale].scale; - period = clk / freqHz; - if (period <= 65536) { - baseUs = 1000000.0f / clk; - break; - } - if (++scale >= PwmScale.values().length) { - throw new IllegalArgumentException("Frequency too low: " - + freqHz); - } - } - - PwmImpl pwm = new PwmImpl(this, spec.pin, pwmNum, period, baseUs); - addDisconnectListener(pwm); - openPins_[spec.pin] = true; - try { - protocol_.setPinDigitalOut(spec.pin, false, spec.mode); - protocol_.setPinPwm(spec.pin, pwmNum, true); - protocol_.setPwmPeriod(pwmNum, period - 1, - IOIOProtocol.PwmScale.values()[scale]); - } catch (IOException e) { - pwm.close(); - throw new ConnectionLostException(e); - } - return pwm; - } - - @Override - public Uart openUart(int rx, int tx, int baud, Uart.Parity parity, - Uart.StopBits stopbits) throws ConnectionLostException { - return openUart(rx == INVALID_PIN ? null : new DigitalInput.Spec(rx), - tx == INVALID_PIN ? null : new DigitalOutput.Spec(tx), baud, - parity, stopbits); - } - - @Override - synchronized public Uart openUart(DigitalInput.Spec rx, - DigitalOutput.Spec tx, int baud, Uart.Parity parity, - Uart.StopBits stopbits) throws ConnectionLostException { - checkState(); - if (rx != null) { - PinFunctionMap.checkSupportsPeripheralInput(rx.pin); - checkPinFree(rx.pin); - } - if (tx != null) { - PinFunctionMap.checkSupportsPeripheralOutput(tx.pin); - checkPinFree(tx.pin); - } - int rxPin = rx != null ? rx.pin : INVALID_PIN; - int txPin = tx != null ? tx.pin : INVALID_PIN; - int uartNum = uartAllocator_.allocateModule(); - UartImpl uart = new UartImpl(this, txPin, rxPin, uartNum); - addDisconnectListener(uart); - incomingState_.addUartListener(uartNum, uart); - try { - if (rx != null) { - openPins_[rx.pin] = true; - protocol_.setPinDigitalIn(rx.pin, rx.mode); - protocol_.setPinUart(rx.pin, uartNum, false, true); - } - if (tx != null) { - openPins_[tx.pin] = true; - protocol_.setPinDigitalOut(tx.pin, true, tx.mode); - protocol_.setPinUart(tx.pin, uartNum, true, true); - } - boolean speed4x = true; - int rate = Math.round(4000000.0f / baud) - 1; - if (rate > 65535) { - speed4x = false; - rate = Math.round(1000000.0f / baud) - 1; - } - protocol_.uartConfigure(uartNum, rate, speed4x, stopbits, parity); - } catch (IOException e) { - uart.close(); - throw new ConnectionLostException(e); - } - return uart; - } - - @Override - synchronized public TwiMaster openTwiMaster(int twiNum, Rate rate, - boolean smbus) throws ConnectionLostException { - checkState(); - checkTwiFree(twiNum); - checkPinFree(Constants.TWI_PINS[twiNum][0]); - checkPinFree(Constants.TWI_PINS[twiNum][1]); - openPins_[Constants.TWI_PINS[twiNum][0]] = true; - openPins_[Constants.TWI_PINS[twiNum][1]] = true; - openTwi_[twiNum] = true; - TwiMasterImpl twi = new TwiMasterImpl(this, twiNum); - addDisconnectListener(twi); - incomingState_.addTwiListener(twiNum, twi); - try { - protocol_.i2cConfigureMaster(twiNum, rate, smbus); - } catch (IOException e) { - twi.close(); - throw new ConnectionLostException(e); - } - return twi; - } - - @Override - synchronized public IcspMaster openIcspMaster() - throws ConnectionLostException { - checkState(); - checkIcspFree(); - checkPinFree(Constants.ICSP_PINS[0]); - checkPinFree(Constants.ICSP_PINS[1]); - checkPinFree(Constants.ICSP_PINS[2]); - openPins_[Constants.ICSP_PINS[0]] = true; - openPins_[Constants.ICSP_PINS[1]] = true; - openPins_[Constants.ICSP_PINS[2]] = true; - openIcsp_ = true; - IcspMasterImpl icsp = new IcspMasterImpl(this); - addDisconnectListener(icsp); - incomingState_.addIcspListener(icsp); - try { - protocol_.icspOpen(); - } catch (IOException e) { - icsp.close(); - throw new ConnectionLostException(e); - } - return icsp; - } - - @Override - public SpiMaster openSpiMaster(int miso, int mosi, int clk, - int slaveSelect, SpiMaster.Rate rate) - throws ConnectionLostException { - return openSpiMaster(miso, mosi, clk, new int[] { slaveSelect }, rate); - } - - @Override - public SpiMaster openSpiMaster(int miso, int mosi, int clk, - int[] slaveSelect, SpiMaster.Rate rate) - throws ConnectionLostException { - DigitalOutput.Spec[] slaveSpecs = new DigitalOutput.Spec[slaveSelect.length]; - for (int i = 0; i < slaveSelect.length; ++i) { - slaveSpecs[i] = new DigitalOutput.Spec(slaveSelect[i]); - } - return openSpiMaster(new DigitalInput.Spec(miso, Mode.PULL_UP), - new DigitalOutput.Spec(mosi), new DigitalOutput.Spec(clk), - slaveSpecs, new SpiMaster.Config(rate)); - } - - @Override - synchronized public SpiMaster openSpiMaster(DigitalInput.Spec miso, - DigitalOutput.Spec mosi, DigitalOutput.Spec clk, - DigitalOutput.Spec[] slaveSelect, SpiMaster.Config config) - throws ConnectionLostException { - checkState(); - int ssPins[] = new int[slaveSelect.length]; - checkPinFree(miso.pin); - PinFunctionMap.checkSupportsPeripheralInput(miso.pin); - checkPinFree(mosi.pin); - PinFunctionMap.checkSupportsPeripheralOutput(mosi.pin); - checkPinFree(clk.pin); - PinFunctionMap.checkSupportsPeripheralOutput(clk.pin); - for (int i = 0; i < slaveSelect.length; ++i) { - checkPinFree(slaveSelect[i].pin); - ssPins[i] = slaveSelect[i].pin; - } - - int spiNum = spiAllocator_.allocateModule(); - SpiMasterImpl spi = new SpiMasterImpl(this, spiNum, mosi.pin, miso.pin, - clk.pin, ssPins); - addDisconnectListener(spi); - - openPins_[miso.pin] = true; - openPins_[mosi.pin] = true; - openPins_[clk.pin] = true; - for (int i = 0; i < slaveSelect.length; ++i) { - openPins_[slaveSelect[i].pin] = true; - } - - incomingState_.addSpiListener(spiNum, spi); - try { - protocol_.setPinDigitalIn(miso.pin, miso.mode); - protocol_.setPinSpi(miso.pin, 1, true, spiNum); - protocol_.setPinDigitalOut(mosi.pin, true, mosi.mode); - protocol_.setPinSpi(mosi.pin, 0, true, spiNum); - protocol_.setPinDigitalOut(clk.pin, config.invertClk, clk.mode); - protocol_.setPinSpi(clk.pin, 2, true, spiNum); - for (DigitalOutput.Spec spec : slaveSelect) { - protocol_.setPinDigitalOut(spec.pin, true, spec.mode); - } - protocol_.spiConfigureMaster(spiNum, config); - } catch (IOException e) { - spi.close(); - throw new ConnectionLostException(e); - } - return spi; - } - - @Override - public PulseInput openPulseInput(Spec spec, ClockRate rate, PulseMode mode, - boolean doublePrecision) throws ConnectionLostException { - checkState(); - checkPinFree(spec.pin); - PinFunctionMap.checkSupportsPeripheralInput(spec.pin); - int incapNum = doublePrecision ? incapAllocatorDouble_.allocateModule() - : incapAllocatorSingle_.allocateModule(); - IncapImpl incap = new IncapImpl(this, mode, incapNum, spec.pin, - rate.hertz, mode.scaling, doublePrecision); - addDisconnectListener(incap); - incomingState_.addIncapListener(incapNum, incap); - openPins_[spec.pin] = true; - try { - protocol_.setPinDigitalIn(spec.pin, spec.mode); - protocol_.setPinIncap(spec.pin, incapNum, true); - protocol_.incapConfigure(incapNum, doublePrecision, - mode.ordinal() + 1, rate.ordinal()); - } catch (IOException e) { - incap.close(); - throw new ConnectionLostException(e); - } - return incap; - } - - @Override - public PulseInput openPulseInput(int pin, PulseMode mode) - throws ConnectionLostException { - return openPulseInput(new DigitalInput.Spec(pin), ClockRate.RATE_16MHz, - mode, true); - } - - private void checkPinFree(int pin) { - if (openPins_[pin]) { - throw new IllegalArgumentException("Pin already open: " + pin); - } - } - - private void checkTwiFree(int twi) { - if (openTwi_[twi]) { - throw new IllegalArgumentException("TWI already open: " + twi); - } - } - - private void checkIcspFree() { - if (openIcsp_) { - throw new IllegalArgumentException("ICSP already open"); - } - } - - private void checkState() throws ConnectionLostException { - if (state_ == State.DEAD) { - throw new ConnectionLostException(); - } - if (state_ == State.INCOMPATIBLE) { - throw new IllegalStateException( - "Incompatibility has been reported - IOIO cannot be used"); - } - if (state_ != State.CONNECTED) { - throw new IllegalStateException( - "Connection has not yet been established"); - } - } - - @Override - public synchronized void beginBatch() throws ConnectionLostException { - checkState(); - protocol_.beginBatch(); - } - - @Override - public synchronized void endBatch() throws ConnectionLostException { - checkState(); - try { - protocol_.endBatch(); - } catch (IOException e) { - throw new ConnectionLostException(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.impl; + +import ioio.lib.api.AnalogInput; +import ioio.lib.api.DigitalInput; +import ioio.lib.api.DigitalInput.Spec; +import ioio.lib.api.DigitalInput.Spec.Mode; +import ioio.lib.api.DigitalOutput; +import ioio.lib.api.IOIO; +import ioio.lib.api.IOIOConnection; +import ioio.lib.api.IcspMaster; +import ioio.lib.api.PulseInput; +import ioio.lib.api.PulseInput.ClockRate; +import ioio.lib.api.PulseInput.PulseMode; +import ioio.lib.api.PwmOutput; +import ioio.lib.api.SpiMaster; +import ioio.lib.api.TwiMaster; +import ioio.lib.api.TwiMaster.Rate; +import ioio.lib.api.Uart; +import ioio.lib.api.exception.ConnectionLostException; +import ioio.lib.api.exception.IncompatibilityException; +import ioio.lib.impl.IOIOProtocol.PwmScale; +import ioio.lib.impl.IncomingState.DisconnectListener; + +import java.io.IOException; + +import android.util.Log; + +public class IOIOImpl implements IOIO, DisconnectListener { + private static final String TAG = "IOIOImpl"; + private boolean disconnect_ = false; + + private static final byte[] REQUIRED_INTERFACE_ID = new byte[] { 'I', 'O', + 'I', 'O', '0', '0', '0', '3' }; + + private final IOIOConnection connection_; + private final IncomingState incomingState_ = new IncomingState(); + private final boolean openPins_[] = new boolean[Constants.NUM_PINS]; + private final boolean openTwi_[] = new boolean[Constants.NUM_TWI_MODULES]; + private boolean openIcsp_ = false; + private final ModuleAllocator pwmAllocator_ = new ModuleAllocator( + Constants.NUM_PWM_MODULES, "PWM"); + private final ModuleAllocator uartAllocator_ = new ModuleAllocator( + Constants.NUM_UART_MODULES, "UART"); + private final ModuleAllocator spiAllocator_ = new ModuleAllocator( + Constants.NUM_SPI_MODULES, "SPI"); + private final ModuleAllocator incapAllocatorDouble_ = new ModuleAllocator( + Constants.INCAP_MODULES_DOUBLE, "INCAP_DOUBLE"); + private final ModuleAllocator incapAllocatorSingle_ = new ModuleAllocator( + Constants.INCAP_MODULES_SINGLE, "INCAP_SINGLE"); + IOIOProtocol protocol_; + private State state_ = State.INIT; + + public IOIOImpl(IOIOConnection con) { + connection_ = con; + } + + @Override + public void waitForConnect() throws ConnectionLostException, + IncompatibilityException { + if (state_ == State.CONNECTED) { + return; + } + if (state_ == State.DEAD) { + throw new ConnectionLostException(); + } + addDisconnectListener(this); + Log.d(TAG, "Waiting for IOIO connection"); + try { + try { + Log.v(TAG, "Waiting for underlying connection"); + connection_.waitForConnect(); + synchronized (this) { + if (disconnect_) { + throw new ConnectionLostException(); + } + protocol_ = new IOIOProtocol(connection_.getInputStream(), + connection_.getOutputStream(), incomingState_); + // Once this block exits, a disconnect will also involve + // softClose(). + } + } catch (ConnectionLostException e) { + incomingState_.handleConnectionLost(); + throw e; + } + Log.v(TAG, "Waiting for handshake"); + incomingState_.waitConnectionEstablished(); + Log.v(TAG, "Querying for required interface ID"); + checkInterfaceVersion(); + Log.v(TAG, "Required interface ID is supported"); + state_ = State.CONNECTED; + Log.i(TAG, "IOIO connection established"); + } catch (ConnectionLostException e) { + Log.d(TAG, "Connection lost / aborted"); + state_ = State.DEAD; + throw e; + } catch (InterruptedException e) { + Log.e(TAG, "Unexpected exception", e); + } + } + + @Override + public synchronized void disconnect() { + Log.d(TAG, "Client requested disconnect."); + if (disconnect_) { + return; + } + disconnect_ = true; + try { + if (protocol_ != null) { + protocol_.softClose(); + } + } catch (IOException e) { + Log.e(TAG, "Soft close failed", e); + } + connection_.disconnect(); + } + + @Override + public synchronized void disconnected() { + state_ = State.DEAD; + if (disconnect_) { + return; + } + Log.d(TAG, "Physical disconnect."); + disconnect_ = true; + // The IOIOConnection doesn't necessarily know about the disconnect + connection_.disconnect(); + } + + @Override + public void waitForDisconnect() throws InterruptedException { + incomingState_.waitDisconnect(); + } + + @Override + public State getState() { + return state_; + } + + private void checkInterfaceVersion() throws IncompatibilityException, + ConnectionLostException, InterruptedException { + try { + protocol_.checkInterface(REQUIRED_INTERFACE_ID); + } catch (IOException e) { + throw new ConnectionLostException(e); + } + if (!incomingState_.waitForInterfaceSupport()) { + state_ = State.INCOMPATIBLE; + Log.e(TAG, "Required interface ID is not supported"); + throw new IncompatibilityException( + "IOIO firmware does not support required firmware: " + + new String(REQUIRED_INTERFACE_ID)); + } + } + + synchronized void removeDisconnectListener(DisconnectListener listener) { + incomingState_.removeDisconnectListener(listener); + } + + synchronized void addDisconnectListener(DisconnectListener listener) + throws ConnectionLostException { + incomingState_.addDisconnectListener(listener); + } + + synchronized void closePin(int pin) { + try { + checkState(); + if (!openPins_[pin]) { + throw new IllegalStateException("Pin not open: " + pin); + } + protocol_.setPinDigitalIn(pin, DigitalInput.Spec.Mode.FLOATING); + openPins_[pin] = false; + } catch (IOException e) { + } catch (ConnectionLostException e) { + } + } + + synchronized void closePwm(int pwmNum) { + try { + checkState(); + pwmAllocator_.releaseModule(pwmNum); + protocol_.setPwmPeriod(pwmNum, 0, IOIOProtocol.PwmScale.SCALE_1X); + } catch (IOException e) { + } catch (ConnectionLostException e) { + } + } + + synchronized void closeUart(int uartNum) { + try { + checkState(); + uartAllocator_.releaseModule(uartNum); + protocol_.uartClose(uartNum); + } catch (IOException e) { + } catch (ConnectionLostException e) { + } + } + + synchronized void closeTwi(int twiNum) { + try { + checkState(); + if (!openTwi_[twiNum]) { + throw new IllegalStateException("TWI not open: " + twiNum); + } + openTwi_[twiNum] = false; + openPins_[Constants.TWI_PINS[twiNum][0]] = false; + openPins_[Constants.TWI_PINS[twiNum][1]] = false; + protocol_.i2cClose(twiNum); + } catch (IOException e) { + } catch (ConnectionLostException e) { + } + } + + synchronized void closeIcsp() { + try { + checkState(); + if (!openIcsp_) { + throw new IllegalStateException("ICSP not open"); + } + openIcsp_ = false; + openPins_[Constants.ICSP_PINS[0]] = false; + openPins_[Constants.ICSP_PINS[1]] = false; + protocol_.icspClose(); + } catch (ConnectionLostException e) { + } catch (IOException e) { + } + } + + synchronized void closeSpi(int spiNum) { + try { + checkState(); + spiAllocator_.releaseModule(spiNum); + protocol_.spiClose(spiNum); + } catch (IOException e) { + } catch (ConnectionLostException e) { + } + } + + synchronized void closeIncap(int incapNum, boolean doublePrecision) { + try { + checkState(); + if (doublePrecision) { + incapAllocatorDouble_.releaseModule(incapNum); + } else { + incapAllocatorSingle_.releaseModule(incapNum); + } + protocol_.incapClose(incapNum, doublePrecision); + } catch (IOException e) { + } catch (ConnectionLostException e) { + } + } + + @Override + synchronized public void softReset() throws ConnectionLostException { + checkState(); + try { + protocol_.softReset(); + } catch (IOException e) { + throw new ConnectionLostException(e); + } + } + + @Override + synchronized public void hardReset() throws ConnectionLostException { + checkState(); + try { + protocol_.hardReset(); + } catch (IOException e) { + throw new ConnectionLostException(e); + } + } + + @Override + public String getImplVersion(VersionType v) throws ConnectionLostException { + if (state_ == State.INIT) { + throw new IllegalStateException( + "Connection has not yet been established"); + } + switch (v) { + case HARDWARE_VER: + return incomingState_.hardwareId_; + case BOOTLOADER_VER: + return incomingState_.bootloaderId_; + case APP_FIRMWARE_VER: + return incomingState_.firmwareId_; + case IOIOLIB_VER: + return "IOIO0326"; + } + return null; + } + + @Override + public DigitalInput openDigitalInput(int pin) + throws ConnectionLostException { + return openDigitalInput(new DigitalInput.Spec(pin)); + } + + @Override + public DigitalInput openDigitalInput(int pin, Mode mode) + throws ConnectionLostException { + return openDigitalInput(new DigitalInput.Spec(pin, mode)); + } + + @Override + synchronized public DigitalInput openDigitalInput(DigitalInput.Spec spec) + throws ConnectionLostException { + checkState(); + PinFunctionMap.checkValidPin(spec.pin); + checkPinFree(spec.pin); + DigitalInputImpl result = new DigitalInputImpl(this, spec.pin); + addDisconnectListener(result); + openPins_[spec.pin] = true; + incomingState_.addInputPinListener(spec.pin, result); + try { + protocol_.setPinDigitalIn(spec.pin, spec.mode); + protocol_.setChangeNotify(spec.pin, true); + } catch (IOException e) { + result.close(); + throw new ConnectionLostException(e); + } + return result; + } + + @Override + public DigitalOutput openDigitalOutput(int pin, + ioio.lib.api.DigitalOutput.Spec.Mode mode, boolean startValue) + throws ConnectionLostException { + return openDigitalOutput(new DigitalOutput.Spec(pin, mode), startValue); + } + + @Override + synchronized public DigitalOutput openDigitalOutput( + DigitalOutput.Spec spec, boolean startValue) + throws ConnectionLostException { + checkState(); + PinFunctionMap.checkValidPin(spec.pin); + checkPinFree(spec.pin); + DigitalOutputImpl result = new DigitalOutputImpl(this, spec.pin, startValue); + addDisconnectListener(result); + openPins_[spec.pin] = true; + try { + protocol_.setPinDigitalOut(spec.pin, startValue, spec.mode); + } catch (IOException e) { + result.close(); + throw new ConnectionLostException(e); + } + return result; + } + + @Override + public DigitalOutput openDigitalOutput(int pin, boolean startValue) + throws ConnectionLostException { + return openDigitalOutput(new DigitalOutput.Spec(pin), startValue); + } + + @Override + public DigitalOutput openDigitalOutput(int pin) + throws ConnectionLostException { + return openDigitalOutput(new DigitalOutput.Spec(pin), false); + } + + @Override + synchronized public AnalogInput openAnalogInput(int pin) + throws ConnectionLostException { + checkState(); + PinFunctionMap.checkSupportsAnalogInput(pin); + checkPinFree(pin); + AnalogInputImpl result = new AnalogInputImpl(this, pin); + addDisconnectListener(result); + openPins_[pin] = true; + incomingState_.addInputPinListener(pin, result); + try { + protocol_.setPinAnalogIn(pin); + protocol_.setAnalogInSampling(pin, true); + } catch (IOException e) { + result.close(); + throw new ConnectionLostException(e); + } + return result; + } + + @Override + public PwmOutput openPwmOutput(int pin, int freqHz) + throws ConnectionLostException { + return openPwmOutput(new DigitalOutput.Spec(pin), freqHz); + } + + @Override + synchronized public PwmOutput openPwmOutput(DigitalOutput.Spec spec, + int freqHz) throws ConnectionLostException { + checkState(); + PinFunctionMap.checkSupportsPeripheralOutput(spec.pin); + checkPinFree(spec.pin); + int pwmNum = pwmAllocator_.allocateModule(); + + int scale = 0; + float baseUs; + int period; + while (true) { + final int clk = 16000000 / IOIOProtocol.PwmScale.values()[scale].scale; + period = clk / freqHz; + if (period <= 65536) { + baseUs = 1000000.0f / clk; + break; + } + if (++scale >= PwmScale.values().length) { + throw new IllegalArgumentException("Frequency too low: " + + freqHz); + } + } + + PwmImpl pwm = new PwmImpl(this, spec.pin, pwmNum, period, baseUs); + addDisconnectListener(pwm); + openPins_[spec.pin] = true; + try { + protocol_.setPinDigitalOut(spec.pin, false, spec.mode); + protocol_.setPinPwm(spec.pin, pwmNum, true); + protocol_.setPwmPeriod(pwmNum, period - 1, + IOIOProtocol.PwmScale.values()[scale]); + } catch (IOException e) { + pwm.close(); + throw new ConnectionLostException(e); + } + return pwm; + } + + @Override + public Uart openUart(int rx, int tx, int baud, Uart.Parity parity, + Uart.StopBits stopbits) throws ConnectionLostException { + return openUart(rx == INVALID_PIN ? null : new DigitalInput.Spec(rx), + tx == INVALID_PIN ? null : new DigitalOutput.Spec(tx), baud, + parity, stopbits); + } + + @Override + synchronized public Uart openUart(DigitalInput.Spec rx, + DigitalOutput.Spec tx, int baud, Uart.Parity parity, + Uart.StopBits stopbits) throws ConnectionLostException { + checkState(); + if (rx != null) { + PinFunctionMap.checkSupportsPeripheralInput(rx.pin); + checkPinFree(rx.pin); + } + if (tx != null) { + PinFunctionMap.checkSupportsPeripheralOutput(tx.pin); + checkPinFree(tx.pin); + } + int rxPin = rx != null ? rx.pin : INVALID_PIN; + int txPin = tx != null ? tx.pin : INVALID_PIN; + int uartNum = uartAllocator_.allocateModule(); + UartImpl uart = new UartImpl(this, txPin, rxPin, uartNum); + addDisconnectListener(uart); + incomingState_.addUartListener(uartNum, uart); + try { + if (rx != null) { + openPins_[rx.pin] = true; + protocol_.setPinDigitalIn(rx.pin, rx.mode); + protocol_.setPinUart(rx.pin, uartNum, false, true); + } + if (tx != null) { + openPins_[tx.pin] = true; + protocol_.setPinDigitalOut(tx.pin, true, tx.mode); + protocol_.setPinUart(tx.pin, uartNum, true, true); + } + boolean speed4x = true; + int rate = Math.round(4000000.0f / baud) - 1; + if (rate > 65535) { + speed4x = false; + rate = Math.round(1000000.0f / baud) - 1; + } + protocol_.uartConfigure(uartNum, rate, speed4x, stopbits, parity); + } catch (IOException e) { + uart.close(); + throw new ConnectionLostException(e); + } + return uart; + } + + @Override + synchronized public TwiMaster openTwiMaster(int twiNum, Rate rate, + boolean smbus) throws ConnectionLostException { + checkState(); + checkTwiFree(twiNum); + checkPinFree(Constants.TWI_PINS[twiNum][0]); + checkPinFree(Constants.TWI_PINS[twiNum][1]); + openPins_[Constants.TWI_PINS[twiNum][0]] = true; + openPins_[Constants.TWI_PINS[twiNum][1]] = true; + openTwi_[twiNum] = true; + TwiMasterImpl twi = new TwiMasterImpl(this, twiNum); + addDisconnectListener(twi); + incomingState_.addTwiListener(twiNum, twi); + try { + protocol_.i2cConfigureMaster(twiNum, rate, smbus); + } catch (IOException e) { + twi.close(); + throw new ConnectionLostException(e); + } + return twi; + } + + @Override + synchronized public IcspMaster openIcspMaster() + throws ConnectionLostException { + checkState(); + checkIcspFree(); + checkPinFree(Constants.ICSP_PINS[0]); + checkPinFree(Constants.ICSP_PINS[1]); + checkPinFree(Constants.ICSP_PINS[2]); + openPins_[Constants.ICSP_PINS[0]] = true; + openPins_[Constants.ICSP_PINS[1]] = true; + openPins_[Constants.ICSP_PINS[2]] = true; + openIcsp_ = true; + IcspMasterImpl icsp = new IcspMasterImpl(this); + addDisconnectListener(icsp); + incomingState_.addIcspListener(icsp); + try { + protocol_.icspOpen(); + } catch (IOException e) { + icsp.close(); + throw new ConnectionLostException(e); + } + return icsp; + } + + @Override + public SpiMaster openSpiMaster(int miso, int mosi, int clk, + int slaveSelect, SpiMaster.Rate rate) + throws ConnectionLostException { + return openSpiMaster(miso, mosi, clk, new int[] { slaveSelect }, rate); + } + + @Override + public SpiMaster openSpiMaster(int miso, int mosi, int clk, + int[] slaveSelect, SpiMaster.Rate rate) + throws ConnectionLostException { + DigitalOutput.Spec[] slaveSpecs = new DigitalOutput.Spec[slaveSelect.length]; + for (int i = 0; i < slaveSelect.length; ++i) { + slaveSpecs[i] = new DigitalOutput.Spec(slaveSelect[i]); + } + return openSpiMaster(new DigitalInput.Spec(miso, Mode.PULL_UP), + new DigitalOutput.Spec(mosi), new DigitalOutput.Spec(clk), + slaveSpecs, new SpiMaster.Config(rate)); + } + + @Override + synchronized public SpiMaster openSpiMaster(DigitalInput.Spec miso, + DigitalOutput.Spec mosi, DigitalOutput.Spec clk, + DigitalOutput.Spec[] slaveSelect, SpiMaster.Config config) + throws ConnectionLostException { + checkState(); + int ssPins[] = new int[slaveSelect.length]; + checkPinFree(miso.pin); + PinFunctionMap.checkSupportsPeripheralInput(miso.pin); + checkPinFree(mosi.pin); + PinFunctionMap.checkSupportsPeripheralOutput(mosi.pin); + checkPinFree(clk.pin); + PinFunctionMap.checkSupportsPeripheralOutput(clk.pin); + for (int i = 0; i < slaveSelect.length; ++i) { + checkPinFree(slaveSelect[i].pin); + ssPins[i] = slaveSelect[i].pin; + } + + int spiNum = spiAllocator_.allocateModule(); + SpiMasterImpl spi = new SpiMasterImpl(this, spiNum, mosi.pin, miso.pin, + clk.pin, ssPins); + addDisconnectListener(spi); + + openPins_[miso.pin] = true; + openPins_[mosi.pin] = true; + openPins_[clk.pin] = true; + for (int i = 0; i < slaveSelect.length; ++i) { + openPins_[slaveSelect[i].pin] = true; + } + + incomingState_.addSpiListener(spiNum, spi); + try { + protocol_.setPinDigitalIn(miso.pin, miso.mode); + protocol_.setPinSpi(miso.pin, 1, true, spiNum); + protocol_.setPinDigitalOut(mosi.pin, true, mosi.mode); + protocol_.setPinSpi(mosi.pin, 0, true, spiNum); + protocol_.setPinDigitalOut(clk.pin, config.invertClk, clk.mode); + protocol_.setPinSpi(clk.pin, 2, true, spiNum); + for (DigitalOutput.Spec spec : slaveSelect) { + protocol_.setPinDigitalOut(spec.pin, true, spec.mode); + } + protocol_.spiConfigureMaster(spiNum, config); + } catch (IOException e) { + spi.close(); + throw new ConnectionLostException(e); + } + return spi; + } + + @Override + public PulseInput openPulseInput(Spec spec, ClockRate rate, PulseMode mode, + boolean doublePrecision) throws ConnectionLostException { + checkState(); + checkPinFree(spec.pin); + PinFunctionMap.checkSupportsPeripheralInput(spec.pin); + int incapNum = doublePrecision ? incapAllocatorDouble_.allocateModule() + : incapAllocatorSingle_.allocateModule(); + IncapImpl incap = new IncapImpl(this, mode, incapNum, spec.pin, + rate.hertz, mode.scaling, doublePrecision); + addDisconnectListener(incap); + incomingState_.addIncapListener(incapNum, incap); + openPins_[spec.pin] = true; + try { + protocol_.setPinDigitalIn(spec.pin, spec.mode); + protocol_.setPinIncap(spec.pin, incapNum, true); + protocol_.incapConfigure(incapNum, doublePrecision, + mode.ordinal() + 1, rate.ordinal()); + } catch (IOException e) { + incap.close(); + throw new ConnectionLostException(e); + } + return incap; + } + + @Override + public PulseInput openPulseInput(int pin, PulseMode mode) + throws ConnectionLostException { + return openPulseInput(new DigitalInput.Spec(pin), ClockRate.RATE_16MHz, + mode, true); + } + + private void checkPinFree(int pin) { + if (openPins_[pin]) { + throw new IllegalArgumentException("Pin already open: " + pin); + } + } + + private void checkTwiFree(int twi) { + if (openTwi_[twi]) { + throw new IllegalArgumentException("TWI already open: " + twi); + } + } + + private void checkIcspFree() { + if (openIcsp_) { + throw new IllegalArgumentException("ICSP already open"); + } + } + + private void checkState() throws ConnectionLostException { + if (state_ == State.DEAD) { + throw new ConnectionLostException(); + } + if (state_ == State.INCOMPATIBLE) { + throw new IllegalStateException( + "Incompatibility has been reported - IOIO cannot be used"); + } + if (state_ != State.CONNECTED) { + throw new IllegalStateException( + "Connection has not yet been established"); + } + } + + @Override + public synchronized void beginBatch() throws ConnectionLostException { + checkState(); + protocol_.beginBatch(); + } + + @Override + public synchronized void endBatch() throws ConnectionLostException { + checkState(); + try { + protocol_.endBatch(); + } catch (IOException e) { + throw new ConnectionLostException(e); + } + } +} diff --git a/IOIOLib/src/ioio/lib/impl/IOIOProtocol.java b/IOIOLib/src/ioio/lib/impl/IOIOProtocol.java index 95ac03a..6afb210 100644 --- a/IOIOLib/src/ioio/lib/impl/IOIOProtocol.java +++ b/IOIOLib/src/ioio/lib/impl/IOIOProtocol.java @@ -1,857 +1,862 @@ -/* - * 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.DigitalInput; -import ioio.lib.api.DigitalOutput; -import ioio.lib.api.SpiMaster; -import ioio.lib.api.TwiMaster.Rate; -import ioio.lib.api.Uart; - -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.util.HashSet; -import java.util.Iterator; -import java.util.Set; - -import android.util.Log; - -class IOIOProtocol { - static final int HARD_RESET = 0x00; - static final int ESTABLISH_CONNECTION = 0x00; - static final int SOFT_RESET = 0x01; - static final int CHECK_INTERFACE = 0x02; - static final int CHECK_INTERFACE_RESPONSE = 0x02; - static final int SET_PIN_DIGITAL_OUT = 0x03; - static final int SET_DIGITAL_OUT_LEVEL = 0x04; - static final int REPORT_DIGITAL_IN_STATUS = 0x04; - static final int SET_PIN_DIGITAL_IN = 0x05; - static final int REPORT_PERIODIC_DIGITAL_IN_STATUS = 0x05; - static final int SET_CHANGE_NOTIFY = 0x06; - static final int REGISTER_PERIODIC_DIGITAL_SAMPLING = 0x07; - static final int SET_PIN_PWM = 0x08; - static final int SET_PWM_DUTY_CYCLE = 0x09; - static final int SET_PWM_PERIOD = 0x0A; - static final int SET_PIN_ANALOG_IN = 0x0B; - static final int REPORT_ANALOG_IN_STATUS = 0x0B; - static final int SET_ANALOG_IN_SAMPLING = 0x0C; - static final int REPORT_ANALOG_IN_FORMAT = 0x0C; - static final int UART_CONFIG = 0x0D; - static final int UART_STATUS = 0x0D; - static final int UART_DATA = 0x0E; - static final int SET_PIN_UART = 0x0F; - static final int UART_REPORT_TX_STATUS = 0x0F; - static final int SPI_CONFIGURE_MASTER = 0x10; - static final int SPI_STATUS = 0x10; - static final int SPI_MASTER_REQUEST = 0x11; - static final int SPI_DATA = 0x11; - static final int SET_PIN_SPI = 0x12; - static final int SPI_REPORT_TX_STATUS = 0x12; - static final int I2C_CONFIGURE_MASTER = 0x13; - static final int I2C_STATUS = 0x13; - static final int I2C_WRITE_READ = 0x14; - static final int I2C_RESULT = 0x14; - static final int I2C_REPORT_TX_STATUS = 0x15; - static final int ICSP_SIX = 0x16; - static final int ICSP_REPORT_RX_STATUS = 0x16; - static final int ICSP_REGOUT = 0x17; - static final int ICSP_RESULT = 0x17; - static final int ICSP_PROG_ENTER = 0x18; - static final int ICSP_PROG_EXIT = 0x19; - static final int ICSP_CONFIG = 0x1A; - static final int INCAP_CONFIGURE = 0x1B; - static final int INCAP_STATUS = 0x1B; - static final int SET_PIN_INCAP = 0x1C; - static final int INCAP_REPORT = 0x1C; - static final int SOFT_CLOSE = 0x1D; - - static final int[] SCALE_DIV = new int[] { - 0x1F, // 31.25 - 0x1E, // 35.714 - 0x1D, // 41.667 - 0x1C, // 50 - 0x1B, // 62.5 - 0x1A, // 83.333 - 0x17, // 125 - 0x16, // 142.857 - 0x15, // 166.667 - 0x14, // 200 - 0x13, // 250 - 0x12, // 333.333 - 0x0F, // 500 - 0x0E, // 571.429 - 0x0D, // 666.667 - 0x0C, // 800 - 0x0B, // 1000 - 0x0A, // 1333.333 - 0x07, // 2000 - 0x06, // 2285.714 - 0x05, // 2666.667 - 0x04, // 3200 - 0x03, // 4000 - 0x02, // 5333.333 - 0x01 // 8000 - }; - - private static final String TAG = "IOIOProtocol"; - - enum PwmScale { - SCALE_1X(1, 0), SCALE_8X(8, 3), SCALE_64X(64, 2), SCALE_256X(256, 1); - - public final int scale; - private final int encoding; - - PwmScale(int scale, int encoding) { - this.scale = scale; - this.encoding = encoding; - } - } - - private byte[] outbuf_ = new byte[256]; - private int pos_ = 0; - private int batchCounter_ = 0; - - private void writeByte(int b) throws IOException { - assert (b >= 0 && b < 256); - if (pos_ == outbuf_.length) { - // buffer is full - flush(); - } - //Log.v(TAG, "sending: 0x" + Integer.toHexString(b)); - outbuf_[pos_++] = (byte) b; - } - - public synchronized void beginBatch() { - ++batchCounter_; - } - - public synchronized void endBatch() throws IOException { - if (--batchCounter_ == 0) { - flush(); - } - } - - private void flush() throws IOException { - try { - out_.write(outbuf_, 0, pos_); - } finally { - pos_ = 0; - } - } - - private void writeTwoBytes(int i) throws IOException { - writeByte(i & 0xFF); - writeByte(i >> 8); - } - - private void writeThreeBytes(int i) throws IOException { - writeByte(i & 0xFF); - writeByte((i >> 8) & 0xFF); - writeByte((i >> 16) & 0xFF); - } - - synchronized public void hardReset() throws IOException { - beginBatch(); - writeByte(HARD_RESET); - writeByte('I'); - writeByte('O'); - writeByte('I'); - writeByte('O'); - endBatch(); - } - - synchronized public void softReset() throws IOException { - beginBatch(); - writeByte(SOFT_RESET); - endBatch(); - } - - synchronized public void softClose() throws IOException { - beginBatch(); - writeByte(SOFT_CLOSE); - endBatch(); - } - - synchronized public void checkInterface(byte[] interfaceId) - throws IOException { - if (interfaceId.length != 8) { - throw new IllegalArgumentException( - "interface ID must be exactly 8 bytes long"); - } - beginBatch(); - writeByte(CHECK_INTERFACE); - for (int i = 0; i < 8; ++i) { - writeByte(interfaceId[i]); - } - endBatch(); - } - - synchronized public void setDigitalOutLevel(int pin, boolean level) - throws IOException { - beginBatch(); - writeByte(SET_DIGITAL_OUT_LEVEL); - writeByte(pin << 2 | (level ? 1 : 0)); - endBatch(); - } - - synchronized public void setPinPwm(int pin, int pwmNum, boolean enable) - throws IOException { - beginBatch(); - writeByte(SET_PIN_PWM); - writeByte(pin & 0x3F); - writeByte((enable ? 0x80 : 0x00) | (pwmNum & 0x0F)); - endBatch(); - } - - synchronized public void setPwmDutyCycle(int pwmNum, int dutyCycle, - int fraction) throws IOException { - beginBatch(); - writeByte(SET_PWM_DUTY_CYCLE); - writeByte(pwmNum << 2 | fraction); - writeTwoBytes(dutyCycle); - endBatch(); - } - - synchronized public void setPwmPeriod(int pwmNum, int period, PwmScale scale) - throws IOException { - beginBatch(); - writeByte(SET_PWM_PERIOD); - writeByte(((scale.encoding & 0x02) << 6) | (pwmNum << 1) - | (scale.encoding & 0x01)); - writeTwoBytes(period); - endBatch(); - } - - synchronized public void setPinIncap(int pin, int incapNum, boolean enable) - throws IOException { - beginBatch(); - writeByte(SET_PIN_INCAP); - writeByte(pin); - writeByte(incapNum | (enable ? 0x80 : 0x00)); - endBatch(); - } - - synchronized public void incapClose(int incapNum) throws IOException { - beginBatch(); - writeByte(INCAP_CONFIGURE); - writeByte(incapNum); - writeByte(0x00); - endBatch(); - } - - synchronized public void incapConfigure(int incapNum, boolean double_prec, - int mode, int clock) throws IOException { - beginBatch(); - writeByte(INCAP_CONFIGURE); - writeByte(incapNum); - writeByte((double_prec ? 0x80 : 0x00) | (mode << 3) | clock); - endBatch(); - } - - synchronized public void i2cWriteRead(int i2cNum, boolean tenBitAddr, - int address, int writeSize, int readSize, byte[] writeData) - throws IOException { - beginBatch(); - writeByte(I2C_WRITE_READ); - writeByte(((address >> 8) << 6) | (tenBitAddr ? 0x20 : 0x00) | i2cNum); - writeByte(address & 0xFF); - writeByte(writeSize); - writeByte(readSize); - for (int i = 0; i < writeSize; ++i) { - writeByte(((int) writeData[i]) & 0xFF); - } - endBatch(); - } - - synchronized public void setPinDigitalOut(int pin, boolean value, - DigitalOutput.Spec.Mode mode) throws IOException { - beginBatch(); - writeByte(SET_PIN_DIGITAL_OUT); - writeByte((pin << 2) - | (mode == DigitalOutput.Spec.Mode.OPEN_DRAIN ? 0x01 : 0x00) - | (value ? 0x02 : 0x00)); - endBatch(); - } - - synchronized public void setPinDigitalIn(int pin, - DigitalInput.Spec.Mode mode) throws IOException { - int pull = 0; - if (mode == DigitalInput.Spec.Mode.PULL_UP) { - pull = 1; - } else if (mode == DigitalInput.Spec.Mode.PULL_DOWN) { - pull = 2; - } - beginBatch(); - writeByte(SET_PIN_DIGITAL_IN); - writeByte((pin << 2) | pull); - endBatch(); - } - - synchronized public void setChangeNotify(int pin, boolean changeNotify) - throws IOException { - beginBatch(); - writeByte(SET_CHANGE_NOTIFY); - writeByte((pin << 2) | (changeNotify ? 0x01 : 0x00)); - endBatch(); - } - - synchronized public void registerPeriodicDigitalSampling(int pin, - int freqScale) throws IOException { - // TODO: implement - } - - synchronized public void setPinAnalogIn(int pin) throws IOException { - beginBatch(); - writeByte(SET_PIN_ANALOG_IN); - writeByte(pin); - endBatch(); - } - - synchronized public void setAnalogInSampling(int pin, boolean enable) - throws IOException { - beginBatch(); - writeByte(SET_ANALOG_IN_SAMPLING); - writeByte((enable ? 0x80 : 0x00) | (pin & 0x3F)); - endBatch(); - } - - synchronized public void uartData(int uartNum, int numBytes, byte data[]) - throws IOException { - if (numBytes > 64) { - throw new IllegalArgumentException( - "A maximum of 64 bytes can be sent in one uartData message. Got: " - + numBytes); - } - beginBatch(); - writeByte(UART_DATA); - writeByte((numBytes - 1) | uartNum << 6); - for (int i = 0; i < numBytes; ++i) { - writeByte(((int) data[i]) & 0xFF); - } - endBatch(); - } - - synchronized public void uartConfigure(int uartNum, int rate, - boolean speed4x, Uart.StopBits stopbits, Uart.Parity parity) - throws IOException { - int parbits = parity == Uart.Parity.EVEN ? 1 - : (parity == Uart.Parity.ODD ? 2 : 0); - beginBatch(); - writeByte(UART_CONFIG); - writeByte((uartNum << 6) | (speed4x ? 0x08 : 0x00) - | (stopbits == Uart.StopBits.TWO ? 0x04 : 0x00) | parbits); - writeTwoBytes(rate); - endBatch(); - } - - synchronized public void uartClose(int uartNum) throws IOException { - beginBatch(); - writeByte(UART_CONFIG); - writeByte(uartNum << 6); - writeTwoBytes(0); - endBatch(); - } - - synchronized public void setPinUart(int pin, int uartNum, boolean tx, - boolean enable) throws IOException { - beginBatch(); - writeByte(SET_PIN_UART); - writeByte(pin); - writeByte((enable ? 0x80 : 0x00) | (tx ? 0x40 : 0x00) | uartNum); - endBatch(); - } - - synchronized public void spiConfigureMaster(int spiNum, - SpiMaster.Config config) throws IOException { - beginBatch(); - writeByte(SPI_CONFIGURE_MASTER); - writeByte((spiNum << 5) | SCALE_DIV[config.rate.ordinal()]); - writeByte((config.sampleOnTrailing ? 0x00 : 0x02) - | (config.invertClk ? 0x01 : 0x00)); - endBatch(); - } - - synchronized public void spiClose(int spiNum) throws IOException { - beginBatch(); - writeByte(SPI_CONFIGURE_MASTER); - writeByte(spiNum << 5); - writeByte(0x00); - endBatch(); - } - - synchronized public void setPinSpi(int pin, int mode, boolean enable, - int spiNum) throws IOException { - beginBatch(); - writeByte(SET_PIN_SPI); - writeByte(pin); - writeByte((1 << 4) | (mode << 2) | spiNum); - endBatch(); - } - - synchronized public void spiMasterRequest(int spiNum, int ssPin, - byte data[], int dataBytes, int totalBytes, int responseBytes) - throws IOException { - final boolean dataNeqTotal = (dataBytes != totalBytes); - final boolean resNeqTotal = (responseBytes != totalBytes); - beginBatch(); - writeByte(SPI_MASTER_REQUEST); - writeByte((spiNum << 6) | ssPin); - writeByte((dataNeqTotal ? 0x80 : 0x00) | (resNeqTotal ? 0x40 : 0x00) - | totalBytes - 1); - if (dataNeqTotal) { - writeByte(dataBytes); - } - if (resNeqTotal) { - writeByte(responseBytes); - } - for (int i = 0; i < dataBytes; ++i) { - writeByte(((int) data[i]) & 0xFF); - } - endBatch(); - } - - synchronized public void i2cConfigureMaster(int i2cNum, Rate rate, - boolean smbusLevels) throws IOException { - int rateBits = (rate == Rate.RATE_1MHz ? 3 - : (rate == Rate.RATE_400KHz ? 2 : 1)); - beginBatch(); - writeByte(I2C_CONFIGURE_MASTER); - writeByte((smbusLevels ? 0x80 : 0) | (rateBits << 5) | i2cNum); - endBatch(); - } - - synchronized public void i2cClose(int i2cNum) throws IOException { - beginBatch(); - writeByte(I2C_CONFIGURE_MASTER); - writeByte(i2cNum); - endBatch(); - } - - public void icspOpen() throws IOException { - beginBatch(); - writeByte(ICSP_CONFIG); - writeByte(0x01); - endBatch(); - } - - public void icspClose() throws IOException { - beginBatch(); - writeByte(ICSP_CONFIG); - writeByte(0x00); - endBatch(); - } - - public void icspEnter() throws IOException { - beginBatch(); - writeByte(ICSP_PROG_ENTER); - endBatch(); - } - - public void icspExit() throws IOException { - beginBatch(); - writeByte(ICSP_PROG_EXIT); - endBatch(); - } - - public void icspSix(int instruction) throws IOException { - beginBatch(); - writeByte(ICSP_SIX); - writeThreeBytes(instruction); - endBatch(); - } - - public void icspRegout() throws IOException { - beginBatch(); - writeByte(ICSP_REGOUT); - endBatch(); - } - - public interface IncomingHandler { - public void handleEstablishConnection(byte[] hardwareId, - byte[] bootloaderId, byte[] firmwareId); - - public void handleConnectionLost(); - - public void handleSoftReset(); - - public void handleCheckInterfaceResponse(boolean supported); - - public void handleSetChangeNotify(int pin, boolean changeNotify); - - public void handleReportDigitalInStatus(int pin, boolean level); - - public void handleRegisterPeriodicDigitalSampling(int pin, int freqScale); - - public void handleReportPeriodicDigitalInStatus(int frameNum, - boolean values[]); - - public void handleAnalogPinStatus(int pin, boolean open); - - public void handleReportAnalogInStatus(int pins[], int values[]); - - public void handleUartOpen(int uartNum); - - public void handleUartClose(int uartNum); - - public void handleUartData(int uartNum, int numBytes, byte data[]); - - public void handleUartReportTxStatus(int uartNum, int bytesRemaining); - - public void handleSpiOpen(int spiNum); - - public void handleSpiClose(int spiNum); - - public void handleSpiData(int spiNum, int ssPin, byte data[], - int dataBytes); - - public void handleSpiReportTxStatus(int spiNum, int bytesRemaining); - - public void handleI2cOpen(int i2cNum); - - public void handleI2cClose(int i2cNum); - - public void handleI2cResult(int i2cNum, int size, byte[] data); - - public void handleI2cReportTxStatus(int spiNum, int bytesRemaining); - - void handleIcspOpen(); - - void handleIcspClose(); - - void handleIcspReportRxStatus(int bytesRemaining); - - void handleIcspResult(int size, byte[] data); - - public void handleIncapReport(int incapNum, int size, byte[] data); - - public void handleIncapClose(int incapNum); - - public void handleIncapOpen(int incapNum); - } - - class IncomingThread extends Thread { - private int readOffset_ = 0; - private int validBytes_ = 0; - private byte[] inbuf_ = new byte[64]; - - private int[] analogFramePins_ = new int[0]; - private Set removedPins_ = new HashSet( - Constants.NUM_ANALOG_PINS); - private Set addedPins_ = new HashSet( - Constants.NUM_ANALOG_PINS); - - private void findDelta(int[] newPins) { - removedPins_.clear(); - addedPins_.clear(); - for (int i : analogFramePins_) { - removedPins_.add(i); - } - for (int i : newPins) { - addedPins_.add(i); - } - for (Iterator it = removedPins_.iterator(); it.hasNext();) { - Integer current = it.next(); - if (addedPins_.contains(current)) { - it.remove(); - addedPins_.remove(current); - } - } - } - - private void fillBuf() throws IOException { - try { - validBytes_ = in_.read(inbuf_, 0, inbuf_.length); - if (validBytes_ <= 0) { - throw new IOException("Unexpected stream closure"); - } - //Log.v(TAG, "received " + validBytes_ + " bytes"); - readOffset_ = 0; - } catch (IOException e) { - Log.i(TAG, "IOIO disconnected"); - throw e; - } - } - - private int readByte() throws IOException { - if (readOffset_ == validBytes_) { - fillBuf(); - } - int b = inbuf_[readOffset_++]; - b &= 0xFF; // make unsigned - //Log.v(TAG, "received: 0x" + Integer.toHexString(b)); - return b; - } - - private void readBytes(int size, byte[] buffer) throws IOException { - for (int i = 0; i < size; ++i) { - buffer[i] = (byte) readByte(); - } - } - - @Override - public void run() { - super.run(); - setPriority(MAX_PRIORITY); - int arg1; - int arg2; - int numPins; - int size; - byte[] data = new byte[256]; - try { - while (true) { - switch (arg1 = readByte()) { - case ESTABLISH_CONNECTION: - if (readByte() != 'I' || readByte() != 'O' - || readByte() != 'I' || readByte() != 'O') { - throw new IOException( - "Bad establish connection magic"); - } - byte[] hardwareId = new byte[8]; - byte[] bootloaderId = new byte[8]; - byte[] firmwareId = new byte[8]; - readBytes(8, hardwareId); - readBytes(8, bootloaderId); - readBytes(8, firmwareId); - - handler_.handleEstablishConnection(hardwareId, - bootloaderId, firmwareId); - break; - - case SOFT_RESET: - handler_.handleSoftReset(); - break; - - case REPORT_DIGITAL_IN_STATUS: - arg1 = readByte(); - handler_.handleReportDigitalInStatus(arg1 >> 2, - (arg1 & 0x01) == 1); - break; - - case SET_CHANGE_NOTIFY: - arg1 = readByte(); - handler_.handleSetChangeNotify(arg1 >> 2, - (arg1 & 0x01) == 1); - break; - - case REGISTER_PERIODIC_DIGITAL_SAMPLING: - // TODO: implement - break; - - case REPORT_PERIODIC_DIGITAL_IN_STATUS: - // TODO: implement - break; - - case REPORT_ANALOG_IN_FORMAT: - numPins = readByte(); - int[] newFormat = new int[numPins]; - for (int i = 0; i < numPins; ++i) { - newFormat[i] = readByte(); - } - findDelta(newFormat); - for (Integer i : removedPins_) { - handler_.handleAnalogPinStatus(i, false); - } - for (Integer i : addedPins_) { - handler_.handleAnalogPinStatus(i, true); - } - analogFramePins_ = newFormat; - break; - - case REPORT_ANALOG_IN_STATUS: - numPins = analogFramePins_.length; - int header = 0; - int[] values = new int[numPins]; - for (int i = 0; i < numPins; ++i) { - if (i % 4 == 0) { - header = readByte(); - } - values[i] = (readByte() << 2) | (header & 0x03); - header >>= 2; - } - handler_.handleReportAnalogInStatus(analogFramePins_, - values); - break; - - case UART_REPORT_TX_STATUS: - arg1 = readByte(); - arg2 = readByte(); - handler_.handleUartReportTxStatus(arg1 & 0x03, - (arg1 >> 2) | (arg2 << 6)); - break; - - case UART_DATA: - arg1 = readByte(); - for (int i = 0; i < (arg1 & 0x3F) + 1; ++i) { - data[i] = (byte) readByte(); - } - handler_.handleUartData(arg1 >> 6, (arg1 & 0x3F) + 1, - data); - break; - - case UART_STATUS: - arg1 = readByte(); - if ((arg1 & 0x80) != 0) { - handler_.handleUartOpen(arg1 & 0x03); - } else { - handler_.handleUartClose(arg1 & 0x03); - } - break; - - case SPI_DATA: - arg1 = readByte(); - arg2 = readByte(); - for (int i = 0; i < (arg1 & 0x3F) + 1; ++i) { - data[i] = (byte) readByte(); - } - handler_.handleSpiData(arg1 >> 6, arg2 & 0x3F, data, - (arg1 & 0x3F) + 1); - break; - - case SPI_REPORT_TX_STATUS: - arg1 = readByte(); - arg2 = readByte(); - handler_.handleSpiReportTxStatus(arg1 & 0x03, - (arg1 >> 2) | (arg2 << 6)); - break; - - case SPI_STATUS: - arg1 = readByte(); - if ((arg1 & 0x80) != 0) { - handler_.handleSpiOpen(arg1 & 0x03); - } else { - handler_.handleSpiClose(arg1 & 0x03); - } - break; - - case I2C_STATUS: - arg1 = readByte(); - if ((arg1 & 0x80) != 0) { - handler_.handleI2cOpen(arg1 & 0x03); - } else { - handler_.handleI2cClose(arg1 & 0x03); - } - break; - - case I2C_RESULT: - arg1 = readByte(); - arg2 = readByte(); - if (arg2 != 0xFF) { - for (int i = 0; i < arg2; ++i) { - data[i] = (byte) readByte(); - } - } - handler_.handleI2cResult(arg1 & 0x03, arg2, data); - break; - - case I2C_REPORT_TX_STATUS: - arg1 = readByte(); - arg2 = readByte(); - handler_.handleI2cReportTxStatus(arg1 & 0x03, - (arg1 >> 2) | (arg2 << 6)); - break; - - case CHECK_INTERFACE_RESPONSE: - arg1 = readByte(); - handler_.handleCheckInterfaceResponse((arg1 & 0x01) == 1); - break; - - case ICSP_REPORT_RX_STATUS: - arg1 = readByte(); - arg2 = readByte(); - handler_.handleIcspReportRxStatus(arg1 | (arg2 << 8)); - break; - - case ICSP_RESULT: - data[0] = (byte) readByte(); - data[1] = (byte) readByte(); - handler_.handleIcspResult(2, data); - break; - - case ICSP_CONFIG: - arg1 = readByte(); - if ((arg1 & 0x01) == 1) { - handler_.handleIcspOpen(); - } else { - handler_.handleIcspClose(); - } - break; - - case INCAP_STATUS: - arg1 = readByte(); - if ((arg1 & 0x80) != 0) { - handler_.handleIncapOpen(arg1 & 0x0F); - } else { - handler_.handleIncapClose(arg1 & 0x0F); - } - break; - - case INCAP_REPORT: - arg1 = readByte(); - size = arg1 >> 6; - if (size == 0) { - size = 4; - } - readBytes(size, data); - handler_.handleIncapReport(arg1 & 0x0F, size, data); - break; - - case SOFT_CLOSE: - Log.d(TAG, "Received soft close."); - throw new IOException("Soft close"); - - - default: - in_.close(); - IOException e = new IOException( - "Received unexpected command: 0x" - + Integer.toHexString(arg1)); - Log.e("IOIOProtocol", "Protocol error", e); - throw e; - } - } - } catch (IOException e) { - handler_.handleConnectionLost(); - } - } - } - - private final InputStream in_; - private final OutputStream out_; - private final IncomingHandler handler_; - private final IncomingThread thread_ = new IncomingThread(); - - public IOIOProtocol(InputStream in, OutputStream out, - IncomingHandler handler) { - in_ = in; - out_ = out; - handler_ = handler; - thread_.start(); - } -} +/* + * 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.DigitalInput; +import ioio.lib.api.DigitalOutput; +import ioio.lib.api.SpiMaster; +import ioio.lib.api.TwiMaster.Rate; +import ioio.lib.api.Uart; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Set; + +import android.util.Log; + +class IOIOProtocol { + static final int HARD_RESET = 0x00; + static final int ESTABLISH_CONNECTION = 0x00; + static final int SOFT_RESET = 0x01; + static final int CHECK_INTERFACE = 0x02; + static final int CHECK_INTERFACE_RESPONSE = 0x02; + static final int SET_PIN_DIGITAL_OUT = 0x03; + static final int SET_DIGITAL_OUT_LEVEL = 0x04; + static final int REPORT_DIGITAL_IN_STATUS = 0x04; + static final int SET_PIN_DIGITAL_IN = 0x05; + static final int REPORT_PERIODIC_DIGITAL_IN_STATUS = 0x05; + static final int SET_CHANGE_NOTIFY = 0x06; + static final int REGISTER_PERIODIC_DIGITAL_SAMPLING = 0x07; + static final int SET_PIN_PWM = 0x08; + static final int SET_PWM_DUTY_CYCLE = 0x09; + static final int SET_PWM_PERIOD = 0x0A; + static final int SET_PIN_ANALOG_IN = 0x0B; + static final int REPORT_ANALOG_IN_STATUS = 0x0B; + static final int SET_ANALOG_IN_SAMPLING = 0x0C; + static final int REPORT_ANALOG_IN_FORMAT = 0x0C; + static final int UART_CONFIG = 0x0D; + static final int UART_STATUS = 0x0D; + static final int UART_DATA = 0x0E; + static final int SET_PIN_UART = 0x0F; + static final int UART_REPORT_TX_STATUS = 0x0F; + static final int SPI_CONFIGURE_MASTER = 0x10; + static final int SPI_STATUS = 0x10; + static final int SPI_MASTER_REQUEST = 0x11; + static final int SPI_DATA = 0x11; + static final int SET_PIN_SPI = 0x12; + static final int SPI_REPORT_TX_STATUS = 0x12; + static final int I2C_CONFIGURE_MASTER = 0x13; + static final int I2C_STATUS = 0x13; + static final int I2C_WRITE_READ = 0x14; + static final int I2C_RESULT = 0x14; + static final int I2C_REPORT_TX_STATUS = 0x15; + static final int ICSP_SIX = 0x16; + static final int ICSP_REPORT_RX_STATUS = 0x16; + static final int ICSP_REGOUT = 0x17; + static final int ICSP_RESULT = 0x17; + static final int ICSP_PROG_ENTER = 0x18; + static final int ICSP_PROG_EXIT = 0x19; + static final int ICSP_CONFIG = 0x1A; + static final int INCAP_CONFIGURE = 0x1B; + static final int INCAP_STATUS = 0x1B; + static final int SET_PIN_INCAP = 0x1C; + static final int INCAP_REPORT = 0x1C; + static final int SOFT_CLOSE = 0x1D; + + static final int[] SCALE_DIV = new int[] { + 0x1F, // 31.25 + 0x1E, // 35.714 + 0x1D, // 41.667 + 0x1C, // 50 + 0x1B, // 62.5 + 0x1A, // 83.333 + 0x17, // 125 + 0x16, // 142.857 + 0x15, // 166.667 + 0x14, // 200 + 0x13, // 250 + 0x12, // 333.333 + 0x0F, // 500 + 0x0E, // 571.429 + 0x0D, // 666.667 + 0x0C, // 800 + 0x0B, // 1000 + 0x0A, // 1333.333 + 0x07, // 2000 + 0x06, // 2285.714 + 0x05, // 2666.667 + 0x04, // 3200 + 0x03, // 4000 + 0x02, // 5333.333 + 0x01 // 8000 + }; + + private static final String TAG = "IOIOProtocol"; + + enum PwmScale { + SCALE_1X(1, 0), SCALE_8X(8, 3), SCALE_64X(64, 2), SCALE_256X(256, 1); + + public final int scale; + private final int encoding; + + PwmScale(int scale, int encoding) { + this.scale = scale; + this.encoding = encoding; + } + } + + private byte[] outbuf_ = new byte[256]; + private int pos_ = 0; + private int batchCounter_ = 0; + + private void writeByte(int b) throws IOException { + assert (b >= 0 && b < 256); + if (pos_ == outbuf_.length) { + // buffer is full + flush(); + } + //Log.v(TAG, "sending: 0x" + Integer.toHexString(b)); + outbuf_[pos_++] = (byte) b; + } + + public synchronized void beginBatch() { + ++batchCounter_; + } + + public synchronized void endBatch() throws IOException { + if (--batchCounter_ == 0) { + flush(); + } + } + + private void flush() throws IOException { + try { + out_.write(outbuf_, 0, pos_); + } finally { + pos_ = 0; + } + } + + private void writeTwoBytes(int i) throws IOException { + writeByte(i & 0xFF); + writeByte(i >> 8); + } + + private void writeThreeBytes(int i) throws IOException { + writeByte(i & 0xFF); + writeByte((i >> 8) & 0xFF); + writeByte((i >> 16) & 0xFF); + } + + synchronized public void hardReset() throws IOException { + beginBatch(); + writeByte(HARD_RESET); + writeByte('I'); + writeByte('O'); + writeByte('I'); + writeByte('O'); + endBatch(); + } + + synchronized public void softReset() throws IOException { + beginBatch(); + writeByte(SOFT_RESET); + endBatch(); + } + + synchronized public void softClose() throws IOException { + beginBatch(); + writeByte(SOFT_CLOSE); + endBatch(); + } + + synchronized public void checkInterface(byte[] interfaceId) + throws IOException { + if (interfaceId.length != 8) { + throw new IllegalArgumentException( + "interface ID must be exactly 8 bytes long"); + } + beginBatch(); + writeByte(CHECK_INTERFACE); + for (int i = 0; i < 8; ++i) { + writeByte(interfaceId[i]); + } + endBatch(); + } + + synchronized public void setDigitalOutLevel(int pin, boolean level) + throws IOException { + beginBatch(); + writeByte(SET_DIGITAL_OUT_LEVEL); + writeByte(pin << 2 | (level ? 1 : 0)); + endBatch(); + } + + synchronized public void setPinPwm(int pin, int pwmNum, boolean enable) + throws IOException { + beginBatch(); + writeByte(SET_PIN_PWM); + writeByte(pin & 0x3F); + writeByte((enable ? 0x80 : 0x00) | (pwmNum & 0x0F)); + endBatch(); + } + + synchronized public void setPwmDutyCycle(int pwmNum, int dutyCycle, + int fraction) throws IOException { + beginBatch(); + writeByte(SET_PWM_DUTY_CYCLE); + writeByte(pwmNum << 2 | fraction); + writeTwoBytes(dutyCycle); + endBatch(); + } + + synchronized public void setPwmPeriod(int pwmNum, int period, PwmScale scale) + throws IOException { + beginBatch(); + writeByte(SET_PWM_PERIOD); + writeByte(((scale.encoding & 0x02) << 6) | (pwmNum << 1) + | (scale.encoding & 0x01)); + writeTwoBytes(period); + endBatch(); + } + + synchronized public void setPinIncap(int pin, int incapNum, boolean enable) + throws IOException { + beginBatch(); + writeByte(SET_PIN_INCAP); + writeByte(pin); + writeByte(incapNum | (enable ? 0x80 : 0x00)); + endBatch(); + } + + synchronized public void incapClose(int incapNum, boolean double_prec) + throws IOException { + beginBatch(); + writeByte(INCAP_CONFIGURE); + writeByte(incapNum); + writeByte(double_prec ? 0x80 : 0x00); + endBatch(); + } + + synchronized public void incapConfigure(int incapNum, boolean double_prec, + int mode, int clock) throws IOException { + beginBatch(); + writeByte(INCAP_CONFIGURE); + writeByte(incapNum); + writeByte((double_prec ? 0x80 : 0x00) | (mode << 3) | clock); + endBatch(); + } + + synchronized public void i2cWriteRead(int i2cNum, boolean tenBitAddr, + int address, int writeSize, int readSize, byte[] writeData) + throws IOException { + beginBatch(); + writeByte(I2C_WRITE_READ); + writeByte(((address >> 8) << 6) | (tenBitAddr ? 0x20 : 0x00) | i2cNum); + writeByte(address & 0xFF); + writeByte(writeSize); + writeByte(readSize); + for (int i = 0; i < writeSize; ++i) { + writeByte(((int) writeData[i]) & 0xFF); + } + endBatch(); + } + + synchronized public void setPinDigitalOut(int pin, boolean value, + DigitalOutput.Spec.Mode mode) throws IOException { + beginBatch(); + writeByte(SET_PIN_DIGITAL_OUT); + writeByte((pin << 2) + | (mode == DigitalOutput.Spec.Mode.OPEN_DRAIN ? 0x01 : 0x00) + | (value ? 0x02 : 0x00)); + endBatch(); + } + + synchronized public void setPinDigitalIn(int pin, + DigitalInput.Spec.Mode mode) throws IOException { + int pull = 0; + if (mode == DigitalInput.Spec.Mode.PULL_UP) { + pull = 1; + } else if (mode == DigitalInput.Spec.Mode.PULL_DOWN) { + pull = 2; + } + beginBatch(); + writeByte(SET_PIN_DIGITAL_IN); + writeByte((pin << 2) | pull); + endBatch(); + } + + synchronized public void setChangeNotify(int pin, boolean changeNotify) + throws IOException { + beginBatch(); + writeByte(SET_CHANGE_NOTIFY); + writeByte((pin << 2) | (changeNotify ? 0x01 : 0x00)); + endBatch(); + } + + synchronized public void registerPeriodicDigitalSampling(int pin, + int freqScale) throws IOException { + // TODO: implement + } + + synchronized public void setPinAnalogIn(int pin) throws IOException { + beginBatch(); + writeByte(SET_PIN_ANALOG_IN); + writeByte(pin); + endBatch(); + } + + synchronized public void setAnalogInSampling(int pin, boolean enable) + throws IOException { + beginBatch(); + writeByte(SET_ANALOG_IN_SAMPLING); + writeByte((enable ? 0x80 : 0x00) | (pin & 0x3F)); + endBatch(); + } + + synchronized public void uartData(int uartNum, int numBytes, byte data[]) + throws IOException { + if (numBytes > 64) { + throw new IllegalArgumentException( + "A maximum of 64 bytes can be sent in one uartData message. Got: " + + numBytes); + } + beginBatch(); + writeByte(UART_DATA); + writeByte((numBytes - 1) | uartNum << 6); + for (int i = 0; i < numBytes; ++i) { + writeByte(((int) data[i]) & 0xFF); + } + endBatch(); + } + + synchronized public void uartConfigure(int uartNum, int rate, + boolean speed4x, Uart.StopBits stopbits, Uart.Parity parity) + throws IOException { + int parbits = parity == Uart.Parity.EVEN ? 1 + : (parity == Uart.Parity.ODD ? 2 : 0); + beginBatch(); + writeByte(UART_CONFIG); + writeByte((uartNum << 6) | (speed4x ? 0x08 : 0x00) + | (stopbits == Uart.StopBits.TWO ? 0x04 : 0x00) | parbits); + writeTwoBytes(rate); + endBatch(); + } + + synchronized public void uartClose(int uartNum) throws IOException { + beginBatch(); + writeByte(UART_CONFIG); + writeByte(uartNum << 6); + writeTwoBytes(0); + endBatch(); + } + + synchronized public void setPinUart(int pin, int uartNum, boolean tx, + boolean enable) throws IOException { + beginBatch(); + writeByte(SET_PIN_UART); + writeByte(pin); + writeByte((enable ? 0x80 : 0x00) | (tx ? 0x40 : 0x00) | uartNum); + endBatch(); + } + + synchronized public void spiConfigureMaster(int spiNum, + SpiMaster.Config config) throws IOException { + beginBatch(); + writeByte(SPI_CONFIGURE_MASTER); + writeByte((spiNum << 5) | SCALE_DIV[config.rate.ordinal()]); + writeByte((config.sampleOnTrailing ? 0x00 : 0x02) + | (config.invertClk ? 0x01 : 0x00)); + endBatch(); + } + + synchronized public void spiClose(int spiNum) throws IOException { + beginBatch(); + writeByte(SPI_CONFIGURE_MASTER); + writeByte(spiNum << 5); + writeByte(0x00); + endBatch(); + } + + synchronized public void setPinSpi(int pin, int mode, boolean enable, + int spiNum) throws IOException { + beginBatch(); + writeByte(SET_PIN_SPI); + writeByte(pin); + writeByte((1 << 4) | (mode << 2) | spiNum); + endBatch(); + } + + synchronized public void spiMasterRequest(int spiNum, int ssPin, + byte data[], int dataBytes, int totalBytes, int responseBytes) + throws IOException { + final boolean dataNeqTotal = (dataBytes != totalBytes); + final boolean resNeqTotal = (responseBytes != totalBytes); + beginBatch(); + writeByte(SPI_MASTER_REQUEST); + writeByte((spiNum << 6) | ssPin); + writeByte((dataNeqTotal ? 0x80 : 0x00) | (resNeqTotal ? 0x40 : 0x00) + | totalBytes - 1); + if (dataNeqTotal) { + writeByte(dataBytes); + } + if (resNeqTotal) { + writeByte(responseBytes); + } + for (int i = 0; i < dataBytes; ++i) { + writeByte(((int) data[i]) & 0xFF); + } + endBatch(); + } + + synchronized public void i2cConfigureMaster(int i2cNum, Rate rate, + boolean smbusLevels) throws IOException { + int rateBits = (rate == Rate.RATE_1MHz ? 3 + : (rate == Rate.RATE_400KHz ? 2 : 1)); + beginBatch(); + writeByte(I2C_CONFIGURE_MASTER); + writeByte((smbusLevels ? 0x80 : 0) | (rateBits << 5) | i2cNum); + endBatch(); + } + + synchronized public void i2cClose(int i2cNum) throws IOException { + beginBatch(); + writeByte(I2C_CONFIGURE_MASTER); + writeByte(i2cNum); + endBatch(); + } + + synchronized public void icspOpen() throws IOException { + beginBatch(); + writeByte(ICSP_CONFIG); + writeByte(0x01); + endBatch(); + } + + synchronized public void icspClose() throws IOException { + beginBatch(); + writeByte(ICSP_CONFIG); + writeByte(0x00); + endBatch(); + } + + synchronized public void icspEnter() throws IOException { + beginBatch(); + writeByte(ICSP_PROG_ENTER); + endBatch(); + } + + synchronized public void icspExit() throws IOException { + beginBatch(); + writeByte(ICSP_PROG_EXIT); + endBatch(); + } + + synchronized public void icspSix(int instruction) throws IOException { + beginBatch(); + writeByte(ICSP_SIX); + writeThreeBytes(instruction); + endBatch(); + } + + synchronized public void icspRegout() throws IOException { + beginBatch(); + writeByte(ICSP_REGOUT); + endBatch(); + } + + public interface IncomingHandler { + public void handleEstablishConnection(byte[] hardwareId, + byte[] bootloaderId, byte[] firmwareId); + + public void handleConnectionLost(); + + public void handleSoftReset(); + + public void handleCheckInterfaceResponse(boolean supported); + + public void handleSetChangeNotify(int pin, boolean changeNotify); + + public void handleReportDigitalInStatus(int pin, boolean level); + + public void handleRegisterPeriodicDigitalSampling(int pin, int freqScale); + + public void handleReportPeriodicDigitalInStatus(int frameNum, + boolean values[]); + + public void handleAnalogPinStatus(int pin, boolean open); + + public void handleReportAnalogInStatus(List pins, + List values); + + public void handleUartOpen(int uartNum); + + public void handleUartClose(int uartNum); + + public void handleUartData(int uartNum, int numBytes, byte data[]); + + public void handleUartReportTxStatus(int uartNum, int bytesRemaining); + + public void handleSpiOpen(int spiNum); + + public void handleSpiClose(int spiNum); + + public void handleSpiData(int spiNum, int ssPin, byte data[], + int dataBytes); + + public void handleSpiReportTxStatus(int spiNum, int bytesRemaining); + + public void handleI2cOpen(int i2cNum); + + public void handleI2cClose(int i2cNum); + + public void handleI2cResult(int i2cNum, int size, byte[] data); + + public void handleI2cReportTxStatus(int spiNum, int bytesRemaining); + + void handleIcspOpen(); + + void handleIcspClose(); + + void handleIcspReportRxStatus(int bytesRemaining); + + void handleIcspResult(int size, byte[] data); + + public void handleIncapReport(int incapNum, int size, byte[] data); + + public void handleIncapClose(int incapNum); + + public void handleIncapOpen(int incapNum); + } + + class IncomingThread extends Thread { + private int readOffset_ = 0; + private int validBytes_ = 0; + private byte[] inbuf_ = new byte[64]; + + private List analogPinValues_ = new ArrayList(); + private List analogFramePins_ = new ArrayList(); + private List newFramePins_ = new ArrayList(); + private Set removedPins_ = new HashSet(); + private Set addedPins_ = new HashSet(); + + private void calculateAnalogFrameDelta() { + removedPins_.clear(); + removedPins_.addAll(analogFramePins_); + addedPins_.clear(); + addedPins_.addAll(newFramePins_); + // Remove the intersection from both. + for (Iterator it = removedPins_.iterator(); it.hasNext();) { + Integer current = it.next(); + if (addedPins_.contains(current)) { + it.remove(); + addedPins_.remove(current); + } + } + // swap + List temp = analogFramePins_; + analogFramePins_ = newFramePins_; + newFramePins_ = temp; + } + + private void fillBuf() throws IOException { + try { + validBytes_ = in_.read(inbuf_, 0, inbuf_.length); + if (validBytes_ <= 0) { + throw new IOException("Unexpected stream closure"); + } + //Log.v(TAG, "received " + validBytes_ + " bytes"); + readOffset_ = 0; + } catch (IOException e) { + Log.i(TAG, "IOIO disconnected"); + throw e; + } + } + + private int readByte() throws IOException { + if (readOffset_ == validBytes_) { + fillBuf(); + } + int b = inbuf_[readOffset_++]; + b &= 0xFF; // make unsigned + //Log.v(TAG, "received: 0x" + Integer.toHexString(b)); + return b; + } + + private void readBytes(int size, byte[] buffer) throws IOException { + for (int i = 0; i < size; ++i) { + buffer[i] = (byte) readByte(); + } + } + + @Override + public void run() { + super.run(); + setPriority(MAX_PRIORITY); + int arg1; + int arg2; + int numPins; + int size; + byte[] data = new byte[256]; + try { + while (true) { + switch (arg1 = readByte()) { + case ESTABLISH_CONNECTION: + if (readByte() != 'I' || readByte() != 'O' + || readByte() != 'I' || readByte() != 'O') { + throw new IOException( + "Bad establish connection magic"); + } + byte[] hardwareId = new byte[8]; + byte[] bootloaderId = new byte[8]; + byte[] firmwareId = new byte[8]; + readBytes(8, hardwareId); + readBytes(8, bootloaderId); + readBytes(8, firmwareId); + + handler_.handleEstablishConnection(hardwareId, + bootloaderId, firmwareId); + break; + + case SOFT_RESET: + analogFramePins_.clear(); + handler_.handleSoftReset(); + break; + + case REPORT_DIGITAL_IN_STATUS: + arg1 = readByte(); + handler_.handleReportDigitalInStatus(arg1 >> 2, + (arg1 & 0x01) == 1); + break; + + case SET_CHANGE_NOTIFY: + arg1 = readByte(); + handler_.handleSetChangeNotify(arg1 >> 2, + (arg1 & 0x01) == 1); + break; + + case REGISTER_PERIODIC_DIGITAL_SAMPLING: + // TODO: implement + break; + + case REPORT_PERIODIC_DIGITAL_IN_STATUS: + // TODO: implement + break; + + case REPORT_ANALOG_IN_FORMAT: + numPins = readByte(); + newFramePins_.clear(); + for (int i = 0; i < numPins; ++i) { + newFramePins_.add(readByte()); + } + calculateAnalogFrameDelta(); + for (Integer i : removedPins_) { + handler_.handleAnalogPinStatus(i, false); + } + for (Integer i : addedPins_) { + handler_.handleAnalogPinStatus(i, true); + } + break; + + case REPORT_ANALOG_IN_STATUS: + numPins = analogFramePins_.size(); + int header = 0; + analogPinValues_.clear(); + for (int i = 0; i < numPins; ++i) { + if (i % 4 == 0) { + header = readByte(); + } + analogPinValues_.add((readByte() << 2) | (header & 0x03)); + header >>= 2; + } + handler_.handleReportAnalogInStatus(analogFramePins_, + analogPinValues_); + break; + + case UART_REPORT_TX_STATUS: + arg1 = readByte(); + arg2 = readByte(); + handler_.handleUartReportTxStatus(arg1 & 0x03, + (arg1 >> 2) | (arg2 << 6)); + break; + + case UART_DATA: + arg1 = readByte(); + for (int i = 0; i < (arg1 & 0x3F) + 1; ++i) { + data[i] = (byte) readByte(); + } + handler_.handleUartData(arg1 >> 6, (arg1 & 0x3F) + 1, + data); + break; + + case UART_STATUS: + arg1 = readByte(); + if ((arg1 & 0x80) != 0) { + handler_.handleUartOpen(arg1 & 0x03); + } else { + handler_.handleUartClose(arg1 & 0x03); + } + break; + + case SPI_DATA: + arg1 = readByte(); + arg2 = readByte(); + for (int i = 0; i < (arg1 & 0x3F) + 1; ++i) { + data[i] = (byte) readByte(); + } + handler_.handleSpiData(arg1 >> 6, arg2 & 0x3F, data, + (arg1 & 0x3F) + 1); + break; + + case SPI_REPORT_TX_STATUS: + arg1 = readByte(); + arg2 = readByte(); + handler_.handleSpiReportTxStatus(arg1 & 0x03, + (arg1 >> 2) | (arg2 << 6)); + break; + + case SPI_STATUS: + arg1 = readByte(); + if ((arg1 & 0x80) != 0) { + handler_.handleSpiOpen(arg1 & 0x03); + } else { + handler_.handleSpiClose(arg1 & 0x03); + } + break; + + case I2C_STATUS: + arg1 = readByte(); + if ((arg1 & 0x80) != 0) { + handler_.handleI2cOpen(arg1 & 0x03); + } else { + handler_.handleI2cClose(arg1 & 0x03); + } + break; + + case I2C_RESULT: + arg1 = readByte(); + arg2 = readByte(); + if (arg2 != 0xFF) { + for (int i = 0; i < arg2; ++i) { + data[i] = (byte) readByte(); + } + } + handler_.handleI2cResult(arg1 & 0x03, arg2, data); + break; + + case I2C_REPORT_TX_STATUS: + arg1 = readByte(); + arg2 = readByte(); + handler_.handleI2cReportTxStatus(arg1 & 0x03, + (arg1 >> 2) | (arg2 << 6)); + break; + + case CHECK_INTERFACE_RESPONSE: + arg1 = readByte(); + handler_.handleCheckInterfaceResponse((arg1 & 0x01) == 1); + break; + + case ICSP_REPORT_RX_STATUS: + arg1 = readByte(); + arg2 = readByte(); + handler_.handleIcspReportRxStatus(arg1 | (arg2 << 8)); + break; + + case ICSP_RESULT: + data[0] = (byte) readByte(); + data[1] = (byte) readByte(); + handler_.handleIcspResult(2, data); + break; + + case ICSP_CONFIG: + arg1 = readByte(); + if ((arg1 & 0x01) == 1) { + handler_.handleIcspOpen(); + } else { + handler_.handleIcspClose(); + } + break; + + case INCAP_STATUS: + arg1 = readByte(); + if ((arg1 & 0x80) != 0) { + handler_.handleIncapOpen(arg1 & 0x0F); + } else { + handler_.handleIncapClose(arg1 & 0x0F); + } + break; + + case INCAP_REPORT: + arg1 = readByte(); + size = arg1 >> 6; + if (size == 0) { + size = 4; + } + readBytes(size, data); + handler_.handleIncapReport(arg1 & 0x0F, size, data); + break; + + case SOFT_CLOSE: + Log.d(TAG, "Received soft close."); + throw new IOException("Soft close"); + + + default: + in_.close(); + IOException e = new IOException( + "Received unexpected command: 0x" + + Integer.toHexString(arg1)); + Log.e("IOIOProtocol", "Protocol error", e); + throw e; + } + } + } catch (IOException e) { + handler_.handleConnectionLost(); + } + } + } + + private final InputStream in_; + private final OutputStream out_; + private final IncomingHandler handler_; + private final IncomingThread thread_ = new IncomingThread(); + + public IOIOProtocol(InputStream in, OutputStream out, + IncomingHandler handler) { + in_ = in; + out_ = out; + handler_ = handler; + thread_.start(); + } +} diff --git a/IOIOLib/src/ioio/lib/impl/IncomingState.java b/IOIOLib/src/ioio/lib/impl/IncomingState.java index 05cbccc..a9a34d4 100644 --- a/IOIOLib/src/ioio/lib/impl/IncomingState.java +++ b/IOIOLib/src/ioio/lib/impl/IncomingState.java @@ -32,6 +32,7 @@ import ioio.lib.api.exception.ConnectionLostException; import ioio.lib.impl.IOIOProtocol.IncomingHandler; import java.util.HashSet; +import java.util.List; import java.util.Queue; import java.util.Set; import java.util.concurrent.ConcurrentLinkedQueue; @@ -395,10 +396,11 @@ class IncomingState implements IncomingHandler { } @Override - public void handleReportAnalogInStatus(int pins[], int values[]) { + public void handleReportAnalogInStatus(List pins, + List values) { // logMethod("handleReportAnalogInStatus", pins, values); - for (int i = 0; i < pins.length; ++i) { - intputPinStates_[pins[i]].setValue(values[i]); + for (int i = 0; i < pins.size(); ++i) { + intputPinStates_[pins.get(i)].setValue(values.get(i)); } } diff --git a/IOIOLib/src/ioio/lib/impl/TwiMasterImpl.java b/IOIOLib/src/ioio/lib/impl/TwiMasterImpl.java index 638a5fc..8f7f86b 100644 --- a/IOIOLib/src/ioio/lib/impl/TwiMasterImpl.java +++ b/IOIOLib/src/ioio/lib/impl/TwiMasterImpl.java @@ -137,7 +137,7 @@ class TwiMasterImpl extends AbstractResource implements TwiMaster, synchronized (result) { result.ready_ = true; result.success_ = (size != 0xFF); - if (result.success_) { + if (result.success_ && size > 0) { System.arraycopy(data, 0, result.data_, 0, size); } result.notify(); diff --git a/IOIOLib/src/ioio/lib/spi/NoRuntimeSupportException.java b/IOIOLib/src/ioio/lib/spi/NoRuntimeSupportException.java index 1b6e901..7ad92a5 100644 --- a/IOIOLib/src/ioio/lib/spi/NoRuntimeSupportException.java +++ b/IOIOLib/src/ioio/lib/spi/NoRuntimeSupportException.java @@ -1,6 +1,6 @@ package ioio.lib.spi; -public class NoRuntimeSupportException extends Exception { +public class NoRuntimeSupportException extends RuntimeException { private static final long serialVersionUID = -6559208663699429514L; public NoRuntimeSupportException(String desc) { diff --git a/IOIOLib/src/ioio/lib/util/AbstractIOIOActivity.java b/IOIOLib/src/ioio/lib/util/AbstractIOIOActivity.java index 8408048..0ba3bf3 100644 --- a/IOIOLib/src/ioio/lib/util/AbstractIOIOActivity.java +++ b/IOIOLib/src/ioio/lib/util/AbstractIOIOActivity.java @@ -1,369 +1,369 @@ -/* - * 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 threads_ = new LinkedList(); - private Collection 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}. null - * 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 null 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. - * null 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 null 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 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(); - } - } - -} +/* + * 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 threads_ = new LinkedList(); + private Collection 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}. null + * 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 null 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. + * null 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 null 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 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(); + } + } + +} diff --git a/IOIOLib/src/ioio/lib/util/IOIOConnectionRegistry.java b/IOIOLib/src/ioio/lib/util/IOIOConnectionRegistry.java index 4168b51..acbfa71 100644 --- a/IOIOLib/src/ioio/lib/util/IOIOConnectionRegistry.java +++ b/IOIOLib/src/ioio/lib/util/IOIOConnectionRegistry.java @@ -1,133 +1,131 @@ -/* - * 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. - *

- * For advanced usage only! - *

- * 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 getConnectionFactories() { - Collection result = new LinkedList(); - 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 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 bootstraps_; - - static { - bootstraps_ = new LinkedList(); - String[] classNames = new String[] { "ioio.lib.impl.SocketIOIOConnectionBootstrap" }; - addBootstraps(classNames); - } - - private static void addBootstrap(String className) { - try { - Class 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); - } - } - -} +/* + * 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 ioio.lib.spi.NoRuntimeSupportException; + +import java.util.Collection; +import java.util.LinkedList; + +import android.util.Log; + +/** + * A utility class for managing available connection types to IOIO. + *

+ * For advanced usage only! + *

+ * 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 getConnectionFactories() { + Collection result = new LinkedList(); + 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 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 bootstraps_; + + static { + bootstraps_ = new LinkedList(); + String[] classNames = new String[] { "ioio.lib.impl.SocketIOIOConnectionBootstrap" }; + addBootstraps(classNames); + } + + private static void addBootstrap(String className) { + try { + Class 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 (NoRuntimeSupportException e) { + Log.d(TAG, "No runtime support for: " + className + ". Not adding."); + } catch (Throwable e) { + Log.e(TAG, + "Exception caught while attempting to initialize accessory connection factory", + e); + } + } + +} diff --git a/IOIOLib/src/ioio/lib/util/IOIOLooper.java b/IOIOLib/src/ioio/lib/util/IOIOLooper.java index aa843da..2fffe88 100644 --- a/IOIOLib/src/ioio/lib/util/IOIOLooper.java +++ b/IOIOLib/src/ioio/lib/util/IOIOLooper.java @@ -1,56 +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(); - +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(); + } \ No newline at end of file