Initial commit

This commit is contained in:
2012-01-24 13:04:09 -05:00
commit d0434145ab
248 changed files with 32773 additions and 0 deletions

View File

@@ -0,0 +1,53 @@
/**
* IOIOListener.java
* @date Jan 24, 2012
* @author ricky barrette
* @author Twenty Codes, LLC
*
* Copyright 2012 Richard Barrette
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.TwentyCodes.android.ioio;
import ioio.lib.api.IOIO;
import ioio.lib.api.exception.ConnectionLostException;
/**
* This is a simple interface used to pass information from the IOIO thread to the manager
* @author ricky barrette
*/
public interface IOIOListener {
/**
* Called when a IOIO is connected.
* here is a good time to init ports
* @param ioio
* @author ricky barrette
*/
public void onConnected(IOIO ioio) throws ConnectionLostException;
/**
* Called when the IOIO thread loops.
* Here you want to update the ports
* @author ricky barrette
*/
public void loop() throws ConnectionLostException;
/**
* Called when the IOIO is disconnected.
* @author ricky barrette
*/
public void onDisconnected();
}

View File

@@ -0,0 +1,132 @@
/**
* IOIOManager.java
* @date Jan 21, 2012
* @author ricky barrette
* @author Twenty Codes, LLC
*
* Copyright 2012 Richard Barrette
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.TwentyCodes.android.ioio;
import ioio.lib.bluetooth.BluetoothIOIOConnectionDiscovery;
import ioio.lib.util.IOIOConnectionDiscovery;
import ioio.lib.util.SocketIOIOConnectionDiscovery;
import ioio.lib.util.IOIOConnectionDiscovery.IOIOConnectionSpec;
import java.util.Collection;
import java.util.LinkedList;
import android.util.Log;
/**
* This class manages the IOIO connectivity threads. It is based on the AbstractIOIOActivity
* Remember that onConnected(), loop(), and onDisconnected() are called from the one of the IOIO threads
* @author ricky barrette
*/
public abstract class IOIOManager implements IOIOListener{
private static final String TAG = "IOIOManager";
private Collection<IOIOThread> mThreads = new LinkedList<IOIOThread>();
/**
* Aborts the IOIO connectivity threads and joins them
* @throws InterruptedException
* @author ricky barrette
*/
public void abort() throws InterruptedException {
for (IOIOThread thread : mThreads)
thread.abort();
joinAllThreads();
}
/**
* Joins all the threads
* @throws InterruptedException
* @author ricky barrette
*/
private void joinAllThreads() throws InterruptedException {
for (IOIOThread thread : mThreads)
thread.join();
}
/**
* Creates all the required IOIO connectivity threads
* @author ricky barrette
*/
private void createAllThreads() {
mThreads.clear();
Collection<IOIOConnectionSpec> specs = getConnectionSpecs();
for (IOIOConnectionSpec spec : specs)
mThreads.add(new IOIOThread(spec.className, spec.args, this));
}
/**
* Starts IOIO connectivity threads
* @author ricky barrette
*/
public void start() {
createAllThreads();
for (IOIOThread thread : mThreads)
thread.start();
}
/**
* @return
* @author Ytai Ben-Tsvi
*/
private Collection<IOIOConnectionSpec> getConnectionSpecs() {
Collection<IOIOConnectionSpec> result = new LinkedList<IOIOConnectionSpec>();
addConnectionSpecs(SocketIOIOConnectionDiscovery.class.getName(),result);
addConnectionSpecs(BluetoothIOIOConnectionDiscovery.class.getName(), result);
return result;
}
/**
* @param discoveryClassName
* @param result
* @author Ytai Ben-Tsvi
*/
private void addConnectionSpecs(String discoveryClassName, Collection<IOIOConnectionSpec> result) {
try {
Class<?> cls = Class.forName(discoveryClassName);
IOIOConnectionDiscovery discovery = (IOIOConnectionDiscovery) cls.newInstance();
discovery.getSpecs(result);
} catch (ClassNotFoundException e) {
Log.d(TAG, "Discovery class not found: " + discoveryClassName+ ". Not adding.");
} catch (Exception e) {
Log.w(TAG,"Exception caught while discovering connections - not adding connections of class "+ discoveryClassName, e);
}
}
/**
* @param isStatLedEnabled the isStatLedEnabled to set
* @author ricky barrette
*/
public void setStatLedEnabled(boolean isStatLedEnabled) {
for(IOIOThread thread : mThreads)
thread.setStatLedEnabled(isStatLedEnabled);
}
/**
* Sets the update interval of the IOIO thread
* @param ms
* @author ricky barrette
*/
public void setUpdateInverval(long ms){
for(IOIOThread thread : mThreads)
thread.setUpdateInverval(ms);
}
}

View File

@@ -0,0 +1,161 @@
/**
* IOIOThread.java
* @date Jan 11, 2012
* @author ricky barrette
* @author Ytai Ben-Tsvi
* @author Twenty Codes, LLC
*
* Copyright 2012 Richard Barrette
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.TwentyCodes.android.ioio;
import ioio.lib.api.DigitalOutput;
import ioio.lib.api.IOIO;
import ioio.lib.api.IOIOFactory;
import ioio.lib.api.exception.ConnectionLostException;
/**
* This is the thread that maintains the IOIO interaction.
*
* It first creates a IOIO instance and wait for a connection to be
* established.
*
* Whenever a connection drops, it tries to reconnect, unless this is a
* result of abort().
*
* @author Ytai Ben-Tsvi
* @author ricky barrette
*/
public class IOIOThread extends Thread{
private IOIO mIOIO;
private boolean isAborted = false;
private long mUpdateInterval = 10;
private boolean isStatLedEnabled = false;
private IOIOListener mListener;
private String mClassName;
private Object[] mArgs;
public IOIOThread(IOIOListener listener){
super();
mListener = listener;
}
public IOIOThread(String className, Object[] args, IOIOListener listener) {
super();
mListener = listener;
mClassName = className;
mArgs = args;
}
/**
* Abort the connection.
*
* This is a little tricky synchronization-wise: we need to be handle
* the case of abortion happening before the IOIO instance is created or
* during its creation.
*/
synchronized public void abort() {
isAborted = true;
if (mIOIO != null) {
mIOIO.disconnect();
}
}
/**
* @return the isStatLedEnabled
*/
public boolean isStatLedEnabled() {
return isStatLedEnabled;
}
/**
* Thread Body
* (non-Javadoc)
* @see java.lang.Thread#run()
*/
@Override
public void run() {
while (true) {
synchronized (this) {
if (isAborted) {
break;
}
if(mClassName == null || mArgs == null)
mIOIO = IOIOFactory.create();
else
try {
mIOIO = IOIOFactory.create(mClassName, mArgs);
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
try {
/*
* Here we will try to connect to the IOIO board.
*
* the waitForConnect() is blocking until it can connect
*/
mIOIO.waitForConnect();
/*
* Here we register and initialize each port
*/
DigitalOutput statLed = mIOIO.openDigitalOutput(IOIOValues.STAT_LED_PORT, true);
mListener.onConnected(mIOIO);
/*
* Here we will update the ports every 10 ms (default)
*/
while (true) {
mListener.loop();
statLed.write(!isStatLedEnabled);
sleep(mUpdateInterval );
}
} catch (ConnectionLostException e) {
mListener.onDisconnected();
} catch (Exception e) {
e.printStackTrace();
mIOIO.disconnect();
mListener.onDisconnected();
break;
} finally {
try {
mIOIO.waitForDisconnect();
mListener.onDisconnected();
} catch (InterruptedException e) {
}
}
}
}
/**
* Sets the stat led on / off
* @param isStatLedEnabled the isStatLedEnabled to set
*/
public synchronized void setStatLedEnabled(boolean isStatLedEnabled) {
this.isStatLedEnabled = isStatLedEnabled;
}
/**
* Sets the update interval of the IOIO thread
* @param ms
*/
public synchronized void setUpdateInverval(long ms){
mUpdateInterval = ms;
}
}

View File

@@ -0,0 +1,32 @@
/**
* IOIOValues.java
* @date Jan 24, 2012
* @author ricky barrette
* @author Twenty Codes, LLC
*
* Copyright 2012 Richard Barrette
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.TwentyCodes.android.ioio;
/**
* This class contains values for the IOIO
* @author ricky barrette
*/
public class IOIOValues {
public static final int STAT_LED_PORT = 0 ;
public static final int RC_PWM_FRQ = 50;
}

View File

@@ -0,0 +1,104 @@
/*
* 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 analog input.
* <p>
* An analog input pin can be used to measure voltage. AnalogInput instances are
* obtained by calling {@link IOIO#openAnalogInput(int)}.
* <p>
* Floating-point values scaled from 0 to 1 can be obtained by calling
* {@link #read()}. Absolute voltage levels can be obtained by calling
* {@link #getVoltage()}.
* <p>
* The instance is alive since its creation. The first {@link #read()} call
* block for a few milliseconds until the initial value is updated. If the
* connection with the IOIO drops at any point, the instance transitions to a
* disconnected state, in which every attempt to use the pin (except
* {@link #close()}) will throw a {@link ConnectionLostException}. Whenever
* {@link #close()} is invoked the instance may no longer be used. Any resources
* associated with it are freed and can be reused.
* <p>
* Typical usage:
*
* <pre>
* AnalogInput potentiometer = ioio.openAnalogInput(40);
* float value = potentiometer.read();
* ...
* potentiometer.close(); // pin 40 can now be used for something else.
* </pre>
*
* @see IOIO#openAnalogInput(int)
*/
public interface AnalogInput extends Closeable {
/**
* Gets the analog input reading, as an absolute voltage in Volt units.
* <p>
* It typically takes a few milliseconds between when the instance is
* created and until the first value can be read. In this case, the method
* may block shortly. If this is a problem, the calling thread can be
* interrupted.
* <p>
* If a scaled value is desired, consider using {@link #read()}.
*
* @return The voltage, in Volt units.
* @throws InterruptedException The calling thread has been interrupted.
* @throws ConnectionLostException The connection with the IOIO is lost.
* @see #read()
*/
public float getVoltage() throws InterruptedException,
ConnectionLostException;
/**
* Gets the maximum value against which {@link #read()} values are scaled.
* @return The voltage, in Volts.
*/
public float getReference();
/**
* Gets the analog input reading, as a scaled real value between 0 and 1.
* <p>
* It typically takes a few milliseconds between when the instance is
* created and until the first value can be read. In this case, the method
* may block shortly. If this is a problem, the calling thread can be
* interrupted.
* <p>
* If an absolute value is desired, consider using {@link #getVoltage()}.
*
* @return The voltage, in scaled units.
* @throws InterruptedException The calling thread has been interrupted.
* @throws ConnectionLostException The connection with the IOIO is lost.
* @see #getVoltage()
*/
public float read() throws InterruptedException, ConnectionLostException;
}

View File

@@ -0,0 +1,5 @@
package ioio.lib.api;
public interface Closeable {
void close();
}

View File

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

View File

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

View File

@@ -0,0 +1,638 @@
/*
* 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.
* <p>
* 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.
* <p>
* 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()}.
* <p>
* 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.
* <p>
* 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.
* <p>
* 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.
* <p>
* Typical usage:
*
* <pre>
* 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();
* }
* </pre>
*
* @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
}
/**
* Establishes connection with the IOIO board.
* <p>
* 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().
* <p>
* 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.
* <p>
* 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;
/**
* Resets the entire state (returning to initial state), without dropping
* the connection.
* <p>
* 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.
* <p>
* 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.
* <p>
* 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.
* <p>
* 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.
* <p>
* 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.
* <p>
* 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.
* <p>
* 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.
* <p>
* 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.
* <p>
* 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.
* <p>
* 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.
* <p>
* 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.
* <p>
* 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, PulseMode, boolean)
*/
public PulseInput openPulseInput(int pin, PulseMode mode)
throws ConnectionLostException;
/**
* Open a UART module, enabling a bulk transfer of byte buffers.
* <p>
* UART is a very common hardware communication protocol, enabling full-
* duplex, asynchronous point-to-point data transfer. It typically serves
* for opening consoles or as a basis for higher-level protocols, such as
* MIDI RS-232, and RS-485.
* <p>
* 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.
* <p>
* 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(ioio.lib.api.DigitalInput.Spec, ioio.lib.api.DigitalOutput.Spec, int, Parity, 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(ioio.lib.api.DigitalInput.Spec,
* ioio.lib.api.DigitalOutput.Spec, int, Parity, 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.
* <p>
* 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.
* <p>
* 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.
* <p>
* 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.
* <p>
* 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.
* <p>
* 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.
* <p>
* 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.
* <p>
* 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.
* <p>
* 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;
}

View File

@@ -0,0 +1,44 @@
/*
* 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 java.io.InputStream;
import java.io.OutputStream;
import ioio.lib.api.exception.ConnectionLostException;
public interface IOIOConnection {
void waitForConnect() throws ConnectionLostException;
void disconnect();
InputStream getInputStream() throws ConnectionLostException;
OutputStream getOutputStream() throws ConnectionLostException;
}

View File

@@ -0,0 +1,121 @@
/*
* 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 java.lang.reflect.Constructor;
import ioio.lib.impl.IOIOImpl;
import ioio.lib.impl.SocketIOIOConnection;
/**
* Factory class for creating instances of the IOIO interface.
* <p>
* This class acts as the single entry-point to the IOIO API. It creates the
* bootstrapping between a specific implementation of the IOIO interface and any
* dependencies it might have, such as the underlying connection logic.
* <p>
* Typical usage:
*
* <pre>
* IOIO ioio = IOIOFactory.create();
* try {
* ioio.waitForConnect();
* ...
* ioio.disconnect();
* } catch (ConnectionLostException e) {
* } finally {
* ioio.waitForDisconnect();
* }
* </pre>
*/
public class IOIOFactory {
/** The TCP port used for communicating with the IOIO board. */
public static final int IOIO_PORT = 4545;
/**
* Create a IOIO instance. This specific implementation creates a IOIO
* instance which works with the actual IOIO board connected via a TCP
* connection (typically over a wired USB connection).
*
* @return The IOIO instance.
*/
public static IOIO create() {
try {
return create(SocketIOIOConnection.class.getName(), IOIO_PORT);
} catch (ClassNotFoundException e) {
// we shouldn't get here - this class must always exist.
throw new RuntimeException("Something is very wrong here");
}
}
/**
* Create a IOIO instance with a user-provided underlying connection class.
* This method should be used for establishing a non-standard connection to
* the IOIO board.
*
* @param connectionClassName
* The name of the connection class. Must have a public default
* constructor.
*
* @return The IOIO instance.
* @throws ClassNotFoundException The given class name was not found.
*/
public static IOIO create(String connectionClassName, Object... args) throws ClassNotFoundException {
IOIOConnection connection = createConnectionDynamically(connectionClassName, args);
return create(connection);
}
public static IOIO create(IOIOConnection connection) {
return new IOIOImpl(connection);
}
public static IOIOConnection createConnectionDynamically(
String connectionClassName, Object... args)
throws ClassNotFoundException {
Class<?> cls;
cls = Class.forName(connectionClassName);
Object instance;
try {
Class<?>[] argTypes = new Class<?>[args.length];
for (int i = 0; i < args.length; ++i) {
argTypes[i] = args[i].getClass();
}
Constructor<?> constructor = cls.getConstructor(argTypes);
instance = constructor.newInstance(args);
} catch (Exception e) {
throw new IllegalArgumentException(
"Provided class does not have a public ctor with the right signature", e);
}
if (!(instance instanceof IOIOConnection)) {
throw new IllegalArgumentException(
"Provided class does not implement IOIOConnection");
}
return (IOIOConnection) instance;
}
}

View File

@@ -0,0 +1,145 @@
/*
* 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;
/**
* An interface for controlling an ICSP channel, enabling Flash programming of
* an external PIC MCU, and in particular, another IOIO board.
* <p>
* 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.
* IcspMaster instances are obtained by calling {@link IOIO#openIcspMaster()}.
* <p>
* This interface is very low level: it allows direct access to the atomic
* operations of the ICSP protocol:
* <ul>
* <li>Enter / exit programming mode ( {@link #enterProgramming()} /
* {@link #exitProgramming()}, respectively).</li>
* <li>Executing a single instruction on the slave MCU (
* {@link #executeInstruction(int)}).</li>
* <li>Reading the value of the VISI register of the slave MCU into a read queue
* ({@link #readVisi()}).</li>
* </ul>
* <p>
* The ICSP module uses fixed pins for its lines. See the user guide for details
* for your specific board. ICSP is a special feature, introduced for the
* purpose of programming a IOIO board with another IOIO board. It does not
* necessarily play nicely when used concurrently with other features, in the
* sense that it may introduce latencies in other modules. It is thus
* recommended not to use ICSP in conjunction with latency-sensitive features.
* <p>
* The instance is alive since its creation. If the connection with the IOIO
* drops at any point, the instance transitions to a disconnected state, in
* which every attempt to use it (except {@link #close()}) will throw a
* {@link ConnectionLostException}. Whenever {@link #close()} is invoked the
* instance may no longer be used. Any resources associated with it are freed
* and can be reused.
* <p>
* Typical usage:
*
* <pre>
* {@code
* IcspMaster icsp = ioio.openIcspMaster();
* icsp.enterProgramming();
* icsp.executeInstruction(0x212340); // mov #0x1234, w0
* icsp.executeInstruction(0x883C20); // mov w0, 0x784 (VISI)
* icsp.executeInstruction(0x000000); // nop
* icsp.readVisi();
* int visi = icsp.waitVisiResult(); // should read 0x1234
* icsp.exitProgramming();
* icsp.close(); // free ICSP module and pins
* }</pre>
*
* @see IOIO#openIcspMaster()
*/
public interface IcspMaster extends Closeable {
/**
* Initiate a sequence that will put the slave device in programming mode.
* This sequence is necessary for executing instructions and reading
* register values.
*
* @throws ConnectionLostException
* Connection to the IOIO has been lost.
*/
public void enterProgramming() throws ConnectionLostException;
/**
* Initiate a sequence that will put the slave device out of programming
* mode. It will be held in reset.
*
* @throws ConnectionLostException
* Connection to the IOIO has been lost.
*/
public void exitProgramming() throws ConnectionLostException;
/**
* Execute a single instruction on the slave MCU.
*
* @param instruction
* a 24-bit PIC instruction.
* @throws ConnectionLostException
* Connection to the IOIO has been lost.
*/
public void executeInstruction(int instruction)
throws ConnectionLostException;
/**
* Request a read of the VISI register on the slave MCU. This is an
* asynchronous call, in which the 16-bit result is obtained by
* {@link #waitVisiResult()}.
* This method may block if the read queue on the IOIO is full, but this
* should be for short periods only.
*
* @throws ConnectionLostException
* Connection to the IOIO has been lost.
* @throws InterruptedException
* Interrupted while blocking.
*/
public void readVisi() throws ConnectionLostException, InterruptedException;
/**
* Wait and return a result of a call to {@link #readVisi()}.
* Results will be returned in the same order as requested.
*
* The call will block until there is data, until interrupted, or until
* connection to the IOIO has been lost.
*
* @return The result - an unsigned 16-bit number.
* @throws ConnectionLostException
* Connection to the IOIO has been lost.
* @throws InterruptedException
* Interrupted while blocking.
*/
public int waitVisiResult() throws ConnectionLostException,
InterruptedException;
}

View File

@@ -0,0 +1,322 @@
/*
* 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;
/**
* An interface for pulse width and frequency measurements of digital signals.
* <p>
* PulseInput (commonly known as "input capture") is a versatile module which
* enables extraction of various timing information from a digital signal. There
* are two main use cases: pulse duration measurement and frequency measurement.
* In pulse width measurement we measure the duration of a positive ("high") or
* negative ("low") pulse, i.e. the elapsed time between a rise and a fall or
* vice versa. This mode is useful, for example, for decoding a PWM signal or
* measuring the delay of a sonar return signal. In frequency measurement we
* measure the duration between a rising edge to the following rising edge. This
* gives us a momentary reading of a signal's frequency or period. This is
* commonly used, for example, in conjunction with an optical or magnetic sensor
* for measuring a turning shaft's speed.
* <p>
* {@link PulseInput} instances are obtained by calling
* {@link IOIO#openPulseInput(ioio.lib.api.DigitalInput.Spec, ClockRate, PulseMode, boolean)}
* . When created, some important configuration decisions have to be made: the
* precision (single or double), the clock rate and the mode of operation. Modes
* are straightforward: {@link PulseMode#POSITIVE} is used for measuring a
* positive pulse, {@link PulseMode#NEGATIVE} a negative pulse, and
* {@link PulseMode#FREQ} / {@link PulseMode#FREQ_SCALE_4} /
* {@link PulseMode#FREQ_SCALE_16} are used for measuring frequency. The
* difference between the three scaling modes is that without scaling, the
* frequency is determined by measurement of a single
* (rising-edge-to-rising-edge) period. In x4 scaling, 4 consecutive periods are
* measured and the time is divided by 4, providing some smoothing as well as
* better resolution. Similarly for x16 scaling. Note that scaling affects the
* range of signals to be measured, as discussed below.
* <p>
* The choice of single vs. double-precision is important to understand: IOIO
* internally uses either 16-bit counters or 32-bit counters for the timing. 16-
* counters force us to either limit the maximum duration (and the minimum
* frequency) or compromise accuracy as compared to 32-bit counters. However, if
* you need many concurrent pulse measurements in your application, you may have
* no choice but to use single-precision.
* <p>
* The clock rate selection is important (and even critical when working in
* single-precision) and requires the user to make some assumptions about the
* nature of the measured signal. The higher the clock rate, the more precise
* the measurement, but the longest pulse that can be measured decreases (or
* lowest frequency that can be measured increases). Using the scaling option
* when operating in frequency mode also affects these sizes. combinations. It
* is always recommended to choose the most precise mode, which exceeds the
* maximum expected pulse width (or inverse frequency). If a pulse is received
* whom duration exceeds the longest allowed pulse, it will be "folded" into the
* valid range and product garbage readings.
* <p>
* The following table (sorted by longest pulse) summarizes all possible clock /
* mode combinations. The table applies for <b>single-precision</b> operation.
* For double-precision, simply multiply the longest pulse by 65536 and divide
* the lowest frequency by the same amount. Interestingly, the number written in
* [ms] units in the longest pulse column, roughly corresponds to the same
* number in minutes when working with double precsion, since 1[min] =
* 60000[ms].
* <table border="1">
* <tr>
* <th>Clock</th>
* <th>Scaling</th>
* <th>Resolution</th>
* <th>Longest pulse</th>
* <th>Lowest frequency</th>
* </tr>
* <tr>
* <td>62.5KHz</td>
* <td>1</td>
* <td>16us</td>
* <td>1.048s</td>
* <td>0.95Hz</td>
* </tr>
* <tr>
* <td>250KHz</td>
* <td>1</td>
* <td>4us</td>
* <td>262.1ms</td>
* <td>3.81Hz</td>
* </tr>
* <tr>
* <td>62.5KHz</td>
* <td>4</td>
* <td>4us</td>
* <td>262.1ms</td>
* <td>3.81Hz</td>
* </tr>
* <tr>
* <td>250KHz</td>
* <td>4</td>
* <td>1us</td>
* <td>65.54ms</td>
* <td>15.26Hz</td>
* </tr>
* <tr>
* <td>62.5KHz</td>
* <td>16</td>
* <td>1us</td>
* <td>65.54ms</td>
* <td>15.26Hz</td>
* </tr>
* <tr>
* <td>2MHz</td>
* <td>1</td>
* <td>500ns</td>
* <td>32.77ms</td>
* <td>30.52Hz</td>
* </tr>
* <tr>
* <td>250KHz</td>
* <td>16</td>
* <td>250us</td>
* <td>16.38ms</td>
* <td>61.0Hz</td>
* </tr>
* <tr>
* <td>2MHz</td>
* <td>4</td>
* <td>125ns</td>
* <td>8.192ms</td>
* <td>122.1Hz</td>
* </tr>
* <tr>
* <td>16MHz</td>
* <td>1</td>
* <td>62.5ns</td>
* <td>4.096ms</td>
* <td>244.1Hz</td>
* </tr>
* <tr>
* <td>2MHz</td>
* <td>16</td>
* <td>31.25ns</td>
* <td>2.048ms</td>
* <td>488.3Hz</td>
* </tr>
* <tr>
* <td>16MHz</td>
* <td>4</td>
* <td>15.6ns</td>
* <td>1.024ms</td>
* <td>976.6Hz</td>
* </tr>
* <tr>
* <td>16MHz</td>
* <td>16</td>
* <td>3.9ns</td>
* <td>256us</td>
* <td>3.906KHz</td>
* </tr>
* </table>
*
* <p>
* In some applications it is desirable to measure every incoming pulse rather
* than repetitively query the result of the last measurement. For that purpose
* the {@link #waitPulseGetDuration()} method exists: every incoming pulse width
* is pushed into a small internal queue from which it can be read. The client
* waits for data to be available, then reads it and data that comes in in the
* meanwhile is stored. The queue has limited size, so it is important to read
* quickly if no pulses are to be lost. Note that once a pulse is detected, the
* next one must have its leading edge at least 5ms after the leading edge of
* the current one, or else it will be skipped. This throttling has been
* introduced on purpose, in order to prevent saturation the communication
* channel when the input signal is very high frequency. Effectively, this means
* that the maximum sample rate is 200Hz. This rate has been chosen as it
* enables measure R/C servo signals without missing pulses.
*
* <p>
* Typical usage (servo signal pulse width measurement):
*
* <pre>
* {@code
* // Open pulse input at 16MHz, double-precision
* PulseInput in = ioio.openPulseInput(3, PulseMode.POSITIVE);
* ...
* float widthSec = in.getDuration();
* OR:
* float widthSec = in.waitPulseGetDuration();
* ...
* in.close(); // pin 3 can now be used for something else.
* }
* </pre>
*
* <p>
* Typical usage (frequency measurement):
*
* <pre>
* {@code
* // Signal is known to be slightly over 150Hz. Single precision can be used.
* PulseInput in = ioio.openPulseInput(3,
* ClockRate.RATE_2MHz,
* PulseMode.FREQ_SCALE_4,
* false);
* ...
* float freqHz = in.getFrequency();
* ...
* in.close(); // pin 3 can now be used for something else.
* }
* </pre>
*/
public interface PulseInput extends Closeable {
/** An enumeration for describing the module's operating mode. */
public enum PulseMode {
/** Positive pulse measurement (rising-edge-to-falling-edge). */
POSITIVE(1),
/** Negative pulse measurement (falling-edge-to-rising-edge). */
NEGATIVE(1),
/** Frequency measurement (rising-edge-to-rising-edge). */
FREQ(1),
/** Frequency measurement (rising-edge-to-rising-edge) with 4x scaling. */
FREQ_SCALE_4(4),
/** Frequency measurement (rising-edge-to-rising-edge) with 16x scaling. */
FREQ_SCALE_16(16);
/** The scaling factor as an integer. */
public final int scaling;
private PulseMode(int s) {
scaling = s;
}
}
/** Suported clock rate enum. */
public enum ClockRate {
/** 16MHz */
RATE_16MHz(16000000),
/** 2MHz */
RATE_2MHz(2000000),
/** 250KHz */
RATE_250KHz(250000),
/** 62.5KHz */
RATE_62KHz(62500);
/** The value in Hertz units. */
public final int hertz;
private ClockRate(int h) {
hertz = h;
}
}
/**
* Gets the pulse duration in case of pulse measurement mode, or the period
* in case of frequency mode. When scaling is used, this is compensated for
* here, so the duration of a single cycle will be returned.
* <p>
* The first call to this method may block shortly until the first data
* update arrives. The client may interrupt the calling thread.
*
* @return The duration, in seconds.
* @throws InterruptedException
* The calling thread has been interrupted.
* @throws ConnectionLostException
* The connection with the IOIO has been lost.
*/
public float getDuration() throws InterruptedException,
ConnectionLostException;
/**
* Reads a single measurement from the queue. If the queue is empty, will
* block until more data arrives. The calling thread may be interrupted in
* order to abort the call. See interface documentation for further
* explanation regarding the read queue.
* <p>
* This method may not be used if the interface has was opened in frequency
* mode.
*
* @return The duration, in seconds.
* @throws InterruptedException
* The calling thread has been interrupted.
* @throws ConnectionLostException
* The connection with the IOIO has been lost.
*/
public float waitPulseGetDuration() throws InterruptedException,
ConnectionLostException;
/**
* Gets the momentary frequency of the measured signal. When scaling is
* used, this is compensated for here, so the true frequency of the signal
* will be returned.
* <p>
* The first call to this method may block shortly until the first data
* update arrives. The client may interrupt the calling thread.
*
* @return The frequency, in Hz.
* @throws InterruptedException
* The calling thread has been interrupted.
* @throws ConnectionLostException
* The connection with the IOIO has been lost.
*/
public float getFrequency() throws InterruptedException,
ConnectionLostException;
}

View File

@@ -0,0 +1,126 @@
/*
* 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 PWM (Pulse-Width Modulation) output.
* <p>
* 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. PwmOutput instances are obtained by calling
* {@link IOIO#openPwmOutput(ioio.lib.api.DigitalOutput.Spec, int)}.
* <p>
* When used for motors and LEDs, a frequency of several KHz is typically used,
* where there is a trade-off between switching power-loses and smoothness of
* operation. The pulse width is typically set by specifying the duty cycle,
* with the {@link #setDutyCycle(float)} method. A duty cycle of 0 is "off", a
* duty cycle of 1 is "on", and every intermediate value produces an
* intermediate intensity. Please note that any devices consuming more than 20mA
* of current (e.g. motors) should not by directly connected the the IOIO pins,
* but rather through an amplification circuit suited for the specific load.
* <p>
* When used for hobby servos, the PWM signal is rather used for encoding of the
* desired angle the motor should go to. By standard, a 100Hz signal is used and
* the pulse width is varied between 1ms and 2ms (corresponding to both extremes
* of the shaft angle), using {@link #setPulseWidth(int)}.
* <p>
* The instance is alive since its creation. If the connection with the IOIO
* drops at any point, the instance transitions to a disconnected state, in
* which every attempt to use the pin (except {@link #close()}) will throw a
* {@link ConnectionLostException}. Whenever {@link #close()} is invoked the
* instance may no longer be used. Any resources associated with it are freed
* and can be reused.
* <p>
* Typical usage (fading LED):
*
* <pre>
* PwmOutput servo = ioio.openPwmOutput(12, 1000); // LED anode on pin 12
* ...
* servo.setDutyCycle(0.0f); // LED off
* ...
* servo.setDutyCycle(0.5f); // 50% intensity
* ...
* servo.setDutyCycle(1.0f); // 100% intensity
* ...
* servo.close(); // pin 12 can now be used for something else.
* </pre>
* <p>
* Typical usage (servo):
*
* <pre>
* PwmOutput servo = ioio.openPwmOutput(12, 100);
* ...
* servo.setPulseWidth(1000); // 1000us = 1ms = one extreme
* ...
* servo.setPulseWidth(1500); // 1500us = 1.5ms = center
* ...
* servo.setPulseWidth(2000); // 2000us = 2ms = other extreme
* ...
* servo.close(); // pin 12 can now be used for something else.
* </pre>
*
* @see IOIO#openPwmOutput(ioio.lib.api.DigitalOutput.Spec, int)
*/
public interface PwmOutput extends Closeable {
/**
* Sets the duty cycle of the PWM output. The duty cycle is defined to be
* the pulse width divided by the total cycle period. For absolute control
* of the pulse with, consider using {@link #setPulseWidth(int)}.
*
* @param dutyCycle
* The duty cycle, as a real value from 0.0 to 1.0.
* @throws ConnectionLostException
* The connection to the IOIO has been lost.
* @see #setPulseWidth(int)
*/
public void setDutyCycle(float dutyCycle) throws ConnectionLostException;
/**
* Sets the pulse width of the PWM output. The pulse width is duration of
* the high-time within a single period of the signal. For relative control
* of the pulse with, consider using {@link #setDutyCycle(float)}.
*
* @param pulseWidthUs
* The pulse width, in microsecond units.
* @throws ConnectionLostException
* The connection to the IOIO has been lost.
* @see #setDutyCycle(float)
*/
public void setPulseWidth(int pulseWidthUs) throws ConnectionLostException;
/**
* The same as {@link #setPulseWidth(int)}, but with sub-microsecond
* precision.
*/
public void setPulseWidth(float pulseWidthUs)
throws ConnectionLostException;
}

View File

@@ -0,0 +1,211 @@
/*
* Copyright 2011 Ytai Ben-Tsvi. All rights reserved.
*
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
* of conditions and the following disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL ARSHAN POURSOHI OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* The views and conclusions contained in the software and documentation are those of the
* authors and should not be interpreted as representing official policies, either expressed
* or implied.
*/
package ioio.lib.api;
import ioio.lib.api.DigitalInput.Spec;
import ioio.lib.api.exception.ConnectionLostException;
/**
* An interface for controlling an SPI module, in SPI bus-master mode, enabling
* communication with multiple SPI-enabled slave modules.
* <p>
* 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. SpiMaster instances are obtained by calling
* {@link IOIO#openSpiMaster(Spec, ioio.lib.api.DigitalOutput.Spec, ioio.lib.api.DigitalOutput.Spec, ioio.lib.api.DigitalOutput.Spec[], Config)}.
* <p>
* The SPI protocol is comprised of simultaneous sending and receiving of data
* between the bus master and a single slave. By the very nature of this
* protocol, the amount of bytes sent is equal to the amount of bytes received.
* However, by padding the sent data with garbage data, and by ignoring the
* leading bytes of the received data arbitrarily-sized packets can be sent and
* received.
* <p>
* A very common practice for SPI-based slave devices (although not always the
* case), is to have a fixed request and response length and a fixed lag between
* them, based on the request type. For example, an SPI-based sensor may define
* the the protocol for obtaining its measured value is by sending a 2-byte
* message, whereas the returned 3-byte value has its first byte overlapping the
* second value of the response, as illustrated below:
*
* <pre>
* Master: M1 M2 GG GG
* Slave: GG S1 S2 S3
* </pre>
*
* M1, M2: the master's request<br>
* S1, S2, S3: the slave's response<br>
* GG: garbage bytes used for padding.
* <p>
* The IOIO SPI interface supports such fixed length message protocols using a
* single method, {@link #writeRead(int, byte[], int, int, byte[], int)}, which
* gets the request data, and the lengths of the request, the response and the
* total transaction bytes.
*
* <p>
* The instance is alive since its creation. If the connection with the IOIO
* drops at any point, the instance transitions to a disconnected state, in
* which every attempt to use it (except {@link #close()}) will throw a
* {@link ConnectionLostException}. Whenever {@link #close()} is invoked the
* instance may no longer be used. Any resources associated with it are freed
* and can be reused.
* <p>
* Typical usage (single slave, as per the example above):
*
* <pre>
* {@code
* // MISO, MOSI, CLK, SS on pins 3, 4, 5, 6, respectively.
* SpiMaster spi = ioio.openSpiMaster(3, 4, 5, 6, SpiMaster.Rate.RATE_125K);
* final byte[] request = new byte[]{ 0x23, 0x45 };
* final byte[] response = new byte[3];
* spi.writeRead(request, 2, 4, response, 3);
* ...
* spi.close(); // free SPI module and pins
* }</pre>
*
* @see IOIO#openSpiMaster(Spec, ioio.lib.api.DigitalOutput.Spec, ioio.lib.api.DigitalOutput.Spec, ioio.lib.api.DigitalOutput.Spec[], Config)
*/
public interface SpiMaster extends Closeable {
/** Possible data rates for SPI, in Hz. */
enum Rate {
RATE_31K, RATE_35K, RATE_41K, RATE_50K, RATE_62K, RATE_83K, RATE_125K, RATE_142K, RATE_166K, RATE_200K, RATE_250K, RATE_333K, RATE_500K, RATE_571K, RATE_666K, RATE_800K, RATE_1M, RATE_1_3M, RATE_2M, RATE_2_2M, RATE_2_6M, RATE_3_2M, RATE_4M, RATE_5_3M, RATE_8M
}
/** An object that can be waited on for asynchronous calls. */
public interface Result {
/**
* Wait until the asynchronous call which returned this instance is
* complete.
*
* @throws ConnectionLostException
* Connection with the IOIO has been lost.
* @throws InterruptedException
* This operation has been interrupted.
*/
public void waitReady() throws ConnectionLostException,
InterruptedException;
}
/** SPI configuration structure. */
static class Config {
/** Data rate. */
public Rate rate;
/** Whether to invert clock polarity. */
public boolean invertClk;
/**
* Whether to do the input and output sampling on the trailing clock
* edge.
*/
public boolean sampleOnTrailing;
/**
* Constructor.
*
* @param rate
* Data rate.
* @param invertClk
* Whether to invert clock polarity.
* @param sampleOnTrailing
* Whether to do the input and output sampling on the
* trailing clock edge.
*/
public Config(Rate rate, boolean invertClk, boolean sampleOnTrailing) {
this.rate = rate;
this.invertClk = invertClk;
this.sampleOnTrailing = sampleOnTrailing;
}
/**
* Constructor with common defaults. Equivalent to Config(rate, false,
* false)
*
* @see #Config(Rate, boolean, boolean)
*/
public Config(Rate rate) {
this(rate, false, false);
}
}
/**
* Perform a single SPI transaction which includes optional transmission and
* optional reception of data to a single slave. This is a blocking
* operation that can take a few milliseconds to a few tens of milliseconds.
* To abort this operation, client can interrupt the blocked thread. If
* readSize is 0, the call returns immediately.
*
* @param slave
* The slave index. It is determined by the index of its
* slave-select pin, as per the array passed to
* {@link IOIO#openSpiMaster(Spec, ioio.lib.api.DigitalOutput.Spec, ioio.lib.api.DigitalOutput.Spec, ioio.lib.api.DigitalOutput.Spec[], Config)}
* .
* @param writeData
* A byte array of data to write. May be null if writeSize is 0.
* @param writeSize
* Number of bytes to write. Valid values are 0 to totalSize.
* @param totalSize
* Total transaction length, in bytes. Valid values are 1 to 64.
* @param readData
* An array where the response is to be stored. May be null if
* readSize is 0.
* @param readSize
* The number of expected response bytes. Valid values are 0 to
* totalSize.
* @throws ConnectionLostException
* Connection to the IOIO has been lost.
* @throws InterruptedException
* Calling thread has been interrupted.
*/
public void writeRead(int slave, byte[] writeData, int writeSize,
int totalSize, byte[] readData, int readSize)
throws ConnectionLostException, InterruptedException;
/**
* Shorthand for {@link #writeRead(int, byte[], int, int, byte[], int)} for
* the single-slave case.
*
* @see #writeRead(int, byte[], int, int, byte[], int)
*/
public void writeRead(byte[] writeData, int writeSize, int totalSize,
byte[] readData, int readSize) throws ConnectionLostException,
InterruptedException;
/**
* The same as {@link #writeRead(int, byte[], int, int, byte[], int)}, but
* returns immediately and returns a {@link Result} object that can be
* waited on. If readSize is 0, the result object is ready immediately.
*
* @see #writeRead(int, byte[], int, int, byte[], int)
*/
public Result writeReadAsync(int slave, byte[] writeData, int writeSize,
int totalSize, byte[] readData, int readSize)
throws ConnectionLostException;
}

View File

@@ -0,0 +1,148 @@
/*
* Copyright 2011 Ytai Ben-Tsvi. All rights reserved.
*
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
* of conditions and the following disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL ARSHAN POURSOHI OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* The views and conclusions contained in the software and documentation are those of the
* authors and should not be interpreted as representing official policies, either expressed
* or implied.
*/
package ioio.lib.api;
import ioio.lib.api.exception.ConnectionLostException;
/**
* An interface for controlling a TWI module, in TWI bus-master mode, enabling
* communication with multiple TWI-enabled slave modules.
* <p>
* TWI (Two-Wire Interface) 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. TwiMaster
* instances are obtained by calling
* {@link IOIO#openTwiMaster(int, Rate, boolean)}.
* <p>
* TWI is the generic name for the specific I2C and SMBus protocols, differing
* mostly by the voltage levels they require. This module supports both.
* <p>
* A TWI transaction is comprised of optional sending of a data buffer from the
* master to a single slave, followed by an optional reception of a data buffer
* from that slave. Slaves are designated by addresses, which may be 7-bit
* (common) or 10-bit (less common). TWI transactions may fail, as a result of
* the slave not responding or as result of the slave NACK'ing the request. Such
* a transaction is executed using the
* {@link #writeRead(int, boolean, byte[], int, byte[], int)} method.
* <p>
* The instance is alive since its creation. If the connection with the IOIO
* drops at any point, the instance transitions to a disconnected state, in
* <p>
* The instance is alive since its creation. If the connection with the IOIO
* drops at any point, the instance transitions to a disconnected state, in
* which every attempt to use it (except {@link #close()}) will throw a
* {@link ConnectionLostException}. Whenever {@link #close()} is invoked the
* instance may no longer be used. Any resources associated with it are freed
* and can be reused.
* <p>
* Typical usage:
*
* <pre>
* {@code
* // Uses the SDA1/SCL1 pins, I2C volatege levels at 100KHz.
* TwiMaster twi = ioio.openTwiMaster(1, TwiMaster.RATE_100KHz, false);
* final byte[] request = new byte[]{ 0x23, 0x45 };
* final byte[] response = new byte[3];
* if (twi.writeRead(0x19, false, request, 2, response, 3)) {
* // response is valid
* ...
* } else {
* // handle error
* }
* twi.close(); // free TWI module and pins
* }</pre>
*
* @see IOIO#openTwiMaster(int, Rate, boolean)
*/
public interface TwiMaster extends Closeable {
enum Rate {
RATE_100KHz, RATE_400KHz, RATE_1MHz
}
/** An object that can be waited on for asynchronous calls. */
public interface Result {
/**
* Wait until the asynchronous call which returned this instance is
* complete.
*
* @return true if TWI transaction succeeded.
*
* @throws ConnectionLostException
* Connection with the IOIO has been lost.
* @throws InterruptedException
* This operation has been interrupted.
*/
public boolean waitReady() throws ConnectionLostException,
InterruptedException;
}
/**
* Perform a single TWI transaction which includes optional transmission and
* optional reception of data to a single slave. This is a blocking
* operation that can take a few milliseconds to a few tens of milliseconds.
* To abort this operation, client can interrupt the blocked thread.
*
* @param address
* The slave address, either 7-bit or 10-bit. Note that in some
* TWI device documentation the documented addresses are actually
* 2x the address values used here, as they regard the trailing
* 0-bit as part of the address.
* @param tenBitAddr
* Whether this is a 10-bit addressing mode.
* @param writeData
* The request data.
* @param writeSize
* The number of bytes to write. Valid value are 0-255.
* @param readData
* The array where the response should be stored.
* @param readSize
* The expected number of response bytes. Valid value are 0-255.
* @return Whether operation succeeded.
* @throws ConnectionLostException
* Connection to the IOIO has been lost.
* @throws InterruptedException
* Calling thread has been interrupted.
*/
public boolean writeRead(int address, boolean tenBitAddr, byte[] writeData,
int writeSize, byte[] readData, int readSize)
throws ConnectionLostException, InterruptedException;
/**
* Asynchronous version of
* {@link #writeRead(int, boolean, byte[], int, byte[], int)}. Returns
* immediately and provides a {@link Result} object on which the client can
* wait for the result.
*
* @see #writeRead(int, boolean, byte[], int, byte[], int)
*/
public Result writeReadAsync(int address, boolean tenBitAddr,
byte[] writeData, int writeSize, byte[] readData, int readSize)
throws ConnectionLostException;
}

View File

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

View File

@@ -0,0 +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.api.exception;
/**
* Thrown when the connection between Android and IOIO has been lost or
* disconnected.
*/
public class ConnectionLostException extends Exception {
private static final long serialVersionUID = 7422862446246046772L;
public ConnectionLostException(Exception e) {
super(e);
}
public ConnectionLostException() {
super("Connection lost");
}
}

View File

@@ -0,0 +1,41 @@
/*
* Copyright 2011 Ytai Ben-Tsvi. All rights reserved.
*
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
* of conditions and the following disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL ARSHAN POURSOHI OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* The views and conclusions contained in the software and documentation are those of the
* authors and should not be interpreted as representing official policies, either expressed
* or implied.
*/
package ioio.lib.api.exception;
/**
* Thrown when an incompatibility of system components is detected, such as when
* an unsupported board hardware or software version is encountered.
*/
public class IncompatibilityException extends Exception {
private static final long serialVersionUID = -613939818063932627L;
public IncompatibilityException(String msg) {
super(msg);
}
}

View File

@@ -0,0 +1,14 @@
package ioio.lib.api.exception;
/**
* The IOIO board does not have anymore of the requested resource. This
* exceptions do not need to be handled if the client guarantees that the limits
* on concurrent resource usage are never exceeded.
*/
public class OutOfResourceException extends RuntimeException {
private static final long serialVersionUID = -4482605241361881899L;
public OutOfResourceException(String msg) {
super(msg);
}
}

View File

@@ -0,0 +1,112 @@
package ioio.lib.bluetooth;
import ioio.lib.api.IOIOConnection;
import ioio.lib.api.exception.ConnectionLostException;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.UUID;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothSocket;
import android.util.Log;
public class BluetoothIOIOConnection implements IOIOConnection {
private static final String TAG = "BluetoothIOIOConnection";
private BluetoothSocket socket_ = null;
private boolean disconnect_ = false;
private final String name_;
private final String address_;
public BluetoothIOIOConnection(String name, String address) {
name_ = name;
address_ = address;
}
@Override
public void waitForConnect() throws ConnectionLostException {
final BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
final BluetoothDevice ioioDevice = adapter.getRemoteDevice(address_);
synchronized (this) {
if (disconnect_) {
throw new ConnectionLostException();
}
Log.e(TAG, name_ + " Creating socket");
try {
socket_ = createSocket(ioioDevice);
} catch (IOException e) {
throw new ConnectionLostException(e);
}
Log.e(TAG, name_ + " Created socket");
}
// keep trying to connect as long as we're not aborting
while (true) {
try {
Log.e(TAG, name_ + "Connecting");
socket_.connect();
Log.e(TAG, "Established connection to device " + name_
+ " address: " + address_);
break; // if we got here, we're connected
} catch (Exception e) {
if (disconnect_) {
throw new ConnectionLostException(e);
}
try {
Thread.sleep(1000);
} catch (InterruptedException e1) {
}
}
}
}
public BluetoothSocket createSocket(final BluetoothDevice device)
throws IOException {
try {
// We're trying to create an insecure socket, which is
// only supported
// in API 10 and up. If we fail, we try a secure socket
// with is in API
// 7 and up.
return device.createInsecureRfcommSocketToServiceRecord(UUID
.fromString("00001101-0000-1000-8000-00805F9B34FB"));
} catch (NoSuchMethodError e) {
return device.createRfcommSocketToServiceRecord(UUID
.fromString("00001101-0000-1000-8000-00805F9B34FB"));
}
}
@Override
public synchronized void disconnect() {
if (disconnect_) {
return;
}
Log.d(TAG, "Client initiated disconnect");
disconnect_ = true;
if (socket_ != null) {
try {
socket_.close();
} catch (IOException e) {
}
}
}
@Override
public InputStream getInputStream() throws ConnectionLostException {
try {
return socket_.getInputStream();
} catch (IOException e) {
throw new ConnectionLostException(e);
}
}
@Override
public OutputStream getOutputStream() throws ConnectionLostException {
try {
return socket_.getOutputStream();
} catch (IOException e) {
throw new ConnectionLostException(e);
}
}
}

View File

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

View File

@@ -0,0 +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;
import ioio.lib.api.exception.ConnectionLostException;
public abstract class AbstractPin extends AbstractResource {
protected final int pinNum_;
AbstractPin(IOIOImpl ioio, int pinNum) throws ConnectionLostException {
super(ioio);
pinNum_ = pinNum;
}
synchronized public void close() {
super.close();
ioio_.closePin(pinNum_);
}
}

View File

@@ -0,0 +1,74 @@
/*
* 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.exception.ConnectionLostException;
import ioio.lib.impl.IncomingState.DisconnectListener;
import ioio.lib.api.Closeable;
public class AbstractResource implements Closeable, DisconnectListener {
enum State {
OPEN,
CLOSED,
DISCONNECTED
}
protected State state_ = State.OPEN;
protected final IOIOImpl ioio_;
public AbstractResource(IOIOImpl ioio) throws ConnectionLostException {
ioio_ = ioio;
}
@Override
synchronized public void disconnected() {
if (state_ != State.CLOSED) {
state_ = State.DISCONNECTED;
}
}
synchronized public void close() {
if (state_ == State.CLOSED) {
throw new IllegalStateException("Trying to use a closed resouce");
} else if (state_ == State.DISCONNECTED) {
state_ = State.CLOSED;
return;
}
state_ = State.CLOSED;
ioio_.removeDisconnectListener(this);
}
protected synchronized void checkState() throws ConnectionLostException {
if (state_ == State.CLOSED) {
throw new IllegalStateException("Trying to use a closed resouce");
} else if (state_ == State.DISCONNECTED) {
throw new ConnectionLostException();
}
}
}

View File

@@ -0,0 +1,90 @@
/*
* 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 java.io.IOException;
import ioio.lib.api.AnalogInput;
import ioio.lib.api.exception.ConnectionLostException;
import ioio.lib.impl.IncomingState.InputPinListener;
public class AnalogInputImpl extends AbstractPin implements AnalogInput, InputPinListener {
private int value_;
private boolean valid_ = false;
AnalogInputImpl(IOIOImpl ioio, int pin) throws ConnectionLostException {
super(ioio, pin);
}
@Override
public float getVoltage() throws InterruptedException, ConnectionLostException {
return read() * getReference();
}
@Override
public float getReference() {
return 3.3f;
}
@Override
synchronized public void setValue(int value) {
// Log.v("AnalogInputImpl", "Pin " + pinNum_ + " value is " + value);
assert(value >= 0 || value < 1024);
value_ = value;
if (!valid_) {
valid_ = true;
notifyAll();
}
}
@Override
synchronized public float read() throws InterruptedException, ConnectionLostException {
checkState();
while (!valid_ && state_ != State.DISCONNECTED) {
wait();
}
checkState();
return (float) value_ / 1023.0f;
}
@Override
public synchronized void disconnected() {
super.disconnected();
notifyAll();
}
@Override
public synchronized void close() {
super.close();
try {
ioio_.protocol_.setAnalogInSampling(pinNum_, false);
} catch (IOException e) {
}
}
}

View File

@@ -0,0 +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 };
}

View File

@@ -0,0 +1,91 @@
/*
* 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.exception.ConnectionLostException;
import ioio.lib.impl.IncomingState.InputPinListener;
import java.io.IOException;
public class DigitalInputImpl extends AbstractPin implements DigitalInput,
InputPinListener {
private boolean value_;
private boolean valid_ = false;
DigitalInputImpl(IOIOImpl ioio, int pin) throws ConnectionLostException {
super(ioio, pin);
}
@Override
synchronized public void setValue(int value) {
// Log.v("DigitalInputImpl", "Pin " + pinNum_ + " value is " + value);
assert (value == 0 || value == 1);
value_ = (value == 1);
if (!valid_) {
valid_ = true;
}
notifyAll();
}
synchronized public void waitForValue(boolean value)
throws InterruptedException, ConnectionLostException {
checkState();
while ((!valid_ || value_ != value) && state_ != State.DISCONNECTED) {
wait();
}
checkState();
}
@Override
synchronized public void close() {
super.close();
try {
ioio_.protocol_.setChangeNotify(pinNum_, false);
} catch (IOException e) {
}
}
@Override
synchronized public boolean read() throws InterruptedException,
ConnectionLostException {
checkState();
while (!valid_ && state_ != State.DISCONNECTED) {
wait();
}
checkState();
return value_;
}
@Override
public synchronized void disconnected() {
super.disconnected();
notifyAll();
}
}

View File

@@ -0,0 +1,50 @@
/*
* 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.DigitalOutput;
import ioio.lib.api.exception.ConnectionLostException;
import java.io.IOException;
public class DigitalOutputImpl extends AbstractPin implements DigitalOutput {
DigitalOutputImpl(IOIOImpl ioio, int pin) throws ConnectionLostException {
super(ioio, pin);
}
@Override
synchronized public void write(boolean val) throws ConnectionLostException {
checkState();
try {
ioio_.protocol_.setDigitalOutLevel(pinNum_, val);
} catch (IOException e) {
throw new ConnectionLostException(e);
}
}
}

View File

@@ -0,0 +1,128 @@
/*
* 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 java.io.IOException;
import java.io.OutputStream;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
public class FlowControlledOutputStream extends OutputStream {
interface Sender {
void send(byte[] data, int size);
}
private final Sender sender_;
private final BlockingQueue<Byte> queue_ = new ArrayBlockingQueue<Byte>(
Constants.BUFFER_SIZE);
private final FlushThread thread_ = new FlushThread();
private final int maxPacket_;
private final byte[] packet_;
private int readyToSend_ = 0;
private boolean closed_ = false;
public FlowControlledOutputStream(Sender sender, int maxPacket) {
sender_ = sender;
maxPacket_ = maxPacket;
packet_ = new byte[maxPacket];
thread_.start();
}
@Override
synchronized public void flush() throws IOException {
try {
while (!closed_ && !queue_.isEmpty()) {
wait();
}
} catch (InterruptedException e) {
throw new IOException("Interrupted");
}
if (closed_) {
throw new IOException("Stream has been closed");
}
}
@Override
synchronized public void write(int oneByte) throws IOException {
try {
while (!closed_ && !queue_.offer((byte) oneByte)) {
wait();
}
} catch (InterruptedException e) {
throw new IOException("Interrupted");
}
if (closed_) {
throw new IOException("Stream has been closed");
}
notifyAll();
}
synchronized public void readyToSend(int numBytes) {
readyToSend_ += numBytes;
notifyAll();
}
@Override
synchronized public void close() {
closed_ = true;
notifyAll();
thread_.interrupt();
}
synchronized public void kill() {
thread_.interrupt();
}
class FlushThread extends Thread {
@Override
public void run() {
super.run();
try {
while (true) {
int toSend;
synchronized (FlowControlledOutputStream.this) {
while (readyToSend_ == 0 || queue_.isEmpty()) {
FlowControlledOutputStream.this.wait();
}
toSend = Math.min(maxPacket_,
Math.min(readyToSend_, queue_.size()));
for (int i = 0; i < toSend; ++i) {
packet_[i] = queue_.remove();
}
readyToSend_ -= toSend;
FlowControlledOutputStream.this.notifyAll();
}
sender_.send(packet_, toSend);
}
} catch (InterruptedException e) {
}
}
}
}

View File

@@ -0,0 +1,118 @@
/*
* 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 java.io.IOException;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
public class FlowControlledPacketSender {
interface Packet {
int getSize();
}
interface Sender {
void send(Packet packet);
}
private final Sender sender_;
private final BlockingQueue<Packet> queue_ = new ArrayBlockingQueue<Packet>(
Constants.PACKET_BUFFER_SIZE);
private final FlushThread thread_ = new FlushThread();
private int readyToSend_ = 0;
private boolean closed_ = false;
public FlowControlledPacketSender(Sender sender) {
sender_ = sender;
thread_.start();
}
synchronized public void flush() throws IOException {
try {
while (!closed_ && !queue_.isEmpty()) {
wait();
}
} catch (InterruptedException e) {
throw new IOException("Interrupted");
}
if (closed_) {
throw new IllegalStateException("Stream has been closed");
}
}
synchronized public void write(Packet packet) throws IOException {
try {
while (!closed_ && !queue_.offer(packet)) {
wait();
}
} catch (InterruptedException e) {
throw new IOException("Interrupted");
}
if (closed_) {
throw new IllegalStateException("Stream has been closed");
}
notifyAll();
}
synchronized public void readyToSend(int numBytes) {
readyToSend_ += numBytes;
notifyAll();
}
synchronized public void close() {
closed_ = true;
thread_.interrupt();
}
synchronized public void kill() {
thread_.interrupt();
}
class FlushThread extends Thread {
@Override
public void run() {
super.run();
try {
while (true) {
synchronized (FlowControlledPacketSender.this) {
while (queue_.isEmpty()
|| readyToSend_ < queue_.peek().getSize()) {
FlowControlledPacketSender.this.wait();
}
FlowControlledPacketSender.this.notifyAll();
readyToSend_ -= queue_.peek().getSize();
}
sender_.send(queue_.remove());
}
} catch (InterruptedException e) {
}
}
}
}

View File

@@ -0,0 +1,654 @@
/*
* 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";
enum State {
INIT, CONNECTED, INCOMPATIBLE, DEAD
}
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
synchronized 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.d(TAG, "Waiting for underlying connection");
connection_.waitForConnect();
protocol_ = new IOIOProtocol(connection_.getInputStream(),
connection_.getOutputStream(), incomingState_);
} catch (ConnectionLostException e) {
incomingState_.handleConnectionLost();
throw e;
}
Log.d(TAG, "Waiting for handshake");
incomingState_.waitConnectionEstablished();
Log.d(TAG, "Querying for required interface ID");
checkInterfaceVersion();
Log.d(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 void disconnect() {
connection_.disconnect();
}
@Override
public void disconnected() {
state_ = State.DEAD;
// The IOIOConnection doesn't necessarily know about the disconnect
disconnect();
}
public void waitForDisconnect() throws InterruptedException {
incomingState_.waitDisconnect();
}
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 {
checkState();
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 "IOIO0311";
}
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);
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");
}
}
}

View File

@@ -0,0 +1,798 @@
/*
* 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;
public 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[] 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[128];
private int pos_ = 0;
private void writeByte(int b) {
assert (b >= 0 && b < 256);
//Log.v(TAG, "sending: 0x" + Integer.toHexString(b));
outbuf_[pos_++] = (byte) b;
}
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 {
writeByte(HARD_RESET);
writeByte('I');
writeByte('O');
writeByte('I');
writeByte('O');
flush();
}
synchronized public void softReset() throws IOException {
writeByte(SOFT_RESET);
flush();
}
synchronized public void checkInterface(byte[] interfaceId)
throws IOException {
if (interfaceId.length != 8) {
throw new IllegalArgumentException(
"interface ID must be exactly 8 bytes long");
}
writeByte(CHECK_INTERFACE);
for (int i = 0; i < 8; ++i) {
writeByte(interfaceId[i]);
}
flush();
}
synchronized public void setDigitalOutLevel(int pin, boolean level)
throws IOException {
writeByte(SET_DIGITAL_OUT_LEVEL);
writeByte(pin << 2 | (level ? 1 : 0));
flush();
}
synchronized public void setPinPwm(int pin, int pwmNum, boolean enable)
throws IOException {
writeByte(SET_PIN_PWM);
writeByte(pin & 0x3F);
writeByte((enable ? 0x80 : 0x00) | (pwmNum & 0x0F));
flush();
}
synchronized public void setPwmDutyCycle(int pwmNum, int dutyCycle,
int fraction) throws IOException {
writeByte(SET_PWM_DUTY_CYCLE);
writeByte(pwmNum << 2 | fraction);
writeTwoBytes(dutyCycle);
flush();
}
synchronized public void setPwmPeriod(int pwmNum, int period, PwmScale scale)
throws IOException {
writeByte(SET_PWM_PERIOD);
writeByte(((scale.encoding & 0x02) << 6) | (pwmNum << 1)
| (scale.encoding & 0x01));
writeTwoBytes(period);
flush();
}
synchronized public void setPinIncap(int pin, int incapNum, boolean enable)
throws IOException {
writeByte(SET_PIN_INCAP);
writeByte(pin);
writeByte(incapNum | (enable ? 0x80 : 0x00));
flush();
}
synchronized public void incapClose(int incapNum) throws IOException {
writeByte(INCAP_CONFIGURE);
writeByte(incapNum);
writeByte(0x00);
flush();
}
synchronized public void incapConfigure(int incapNum, boolean double_prec,
int mode, int clock) throws IOException {
writeByte(INCAP_CONFIGURE);
writeByte(incapNum);
writeByte((double_prec ? 0x80 : 0x00) | (mode << 3) | clock);
flush();
}
synchronized public void i2cWriteRead(int i2cNum, boolean tenBitAddr,
int address, int writeSize, int readSize, byte[] writeData)
throws IOException {
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);
}
flush();
}
synchronized public void setPinDigitalOut(int pin, boolean value,
DigitalOutput.Spec.Mode mode) throws IOException {
writeByte(SET_PIN_DIGITAL_OUT);
writeByte((pin << 2)
| (mode == DigitalOutput.Spec.Mode.OPEN_DRAIN ? 0x01 : 0x00)
| (value ? 0x02 : 0x00));
flush();
}
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;
}
writeByte(SET_PIN_DIGITAL_IN);
writeByte((pin << 2) | pull);
flush();
}
synchronized public void setChangeNotify(int pin, boolean changeNotify)
throws IOException {
writeByte(SET_CHANGE_NOTIFY);
writeByte((pin << 2) | (changeNotify ? 0x01 : 0x00));
flush();
}
synchronized public void registerPeriodicDigitalSampling(int pin,
int freqScale) throws IOException {
// TODO: implement
}
synchronized public void setPinAnalogIn(int pin) throws IOException {
writeByte(SET_PIN_ANALOG_IN);
writeByte(pin);
flush();
}
synchronized public void setAnalogInSampling(int pin, boolean enable)
throws IOException {
writeByte(SET_ANALOG_IN_SAMPLING);
writeByte((enable ? 0x80 : 0x00) | (pin & 0x3F));
flush();
}
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);
}
writeByte(UART_DATA);
writeByte((numBytes - 1) | uartNum << 6);
for (int i = 0; i < numBytes; ++i) {
writeByte(((int) data[i]) & 0xFF);
}
flush();
}
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);
writeByte(UART_CONFIG);
writeByte((uartNum << 6) | (speed4x ? 0x08 : 0x00)
| (stopbits == Uart.StopBits.TWO ? 0x04 : 0x00) | parbits);
writeTwoBytes(rate);
flush();
}
synchronized public void uartClose(int uartNum) throws IOException {
writeByte(UART_CONFIG);
writeByte(uartNum << 6);
writeTwoBytes(0);
flush();
}
synchronized public void setPinUart(int pin, int uartNum, boolean tx,
boolean enable) throws IOException {
writeByte(SET_PIN_UART);
writeByte(pin);
writeByte((enable ? 0x80 : 0x00) | (tx ? 0x40 : 0x00) | uartNum);
flush();
}
synchronized public void spiConfigureMaster(int spiNum,
SpiMaster.Config config) throws IOException {
writeByte(SPI_CONFIGURE_MASTER);
writeByte((spiNum << 5) | SCALE_DIV[config.rate.ordinal()]);
writeByte((config.sampleOnTrailing ? 0x00 : 0x02)
| (config.invertClk ? 0x01 : 0x00));
flush();
}
synchronized public void spiClose(int spiNum) throws IOException {
writeByte(SPI_CONFIGURE_MASTER);
writeByte(spiNum << 5);
writeByte(0x00);
flush();
}
synchronized public void setPinSpi(int pin, int mode, boolean enable,
int spiNum) throws IOException {
writeByte(SET_PIN_SPI);
writeByte(pin);
writeByte((1 << 4) | (mode << 2) | spiNum);
flush();
}
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);
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);
}
flush();
}
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));
writeByte(I2C_CONFIGURE_MASTER);
writeByte((smbusLevels ? 0x80 : 0) | (rateBits << 5) | i2cNum);
flush();
}
synchronized public void i2cClose(int i2cNum) throws IOException {
writeByte(I2C_CONFIGURE_MASTER);
writeByte(i2cNum);
flush();
}
public void icspOpen() throws IOException {
writeByte(ICSP_CONFIG);
writeByte(0x01);
flush();
}
public void icspClose() throws IOException {
writeByte(ICSP_CONFIG);
writeByte(0x00);
flush();
}
public void icspEnter() throws IOException {
writeByte(ICSP_PROG_ENTER);
flush();
}
public void icspExit() throws IOException {
writeByte(ICSP_PROG_EXIT);
flush();
}
public void icspSix(int instruction) throws IOException {
writeByte(ICSP_SIX);
writeThreeBytes(instruction);
flush();
}
public void icspRegout() throws IOException {
writeByte(ICSP_REGOUT);
flush();
}
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<Integer> removedPins_ = new HashSet<Integer>(
Constants.NUM_ANALOG_PINS);
private Set<Integer> addedPins_ = new HashSet<Integer>(
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<Integer> 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;
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();
}
}

View File

@@ -0,0 +1,135 @@
/*
* 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.IcspMaster;
import ioio.lib.api.exception.ConnectionLostException;
import ioio.lib.impl.IncomingState.DataModuleListener;
import java.io.IOException;
import java.util.LinkedList;
import java.util.Queue;
public class IcspMasterImpl extends AbstractResource implements IcspMaster,
DataModuleListener {
private Queue<Integer> resultQueue_ = new LinkedList<Integer>();
private int rxRemaining_ = 0;
public IcspMasterImpl(IOIOImpl ioio) throws ConnectionLostException {
super(ioio);
}
@Override
synchronized public void dataReceived(byte[] data, int size) {
assert (size == 2);
int result = (byteToInt(data[1]) << 8) | byteToInt(data[0]);
resultQueue_.add(result);
notifyAll();
}
@Override
synchronized public void reportAdditionalBuffer(int bytesToAdd) {
rxRemaining_ += bytesToAdd;
notifyAll();
}
@Override
synchronized public void enterProgramming() throws ConnectionLostException {
checkState();
try {
ioio_.protocol_.icspEnter();
} catch (IOException e) {
throw new ConnectionLostException(e);
}
}
@Override
synchronized public void exitProgramming() throws ConnectionLostException {
checkState();
try {
ioio_.protocol_.icspExit();
} catch (IOException e) {
throw new ConnectionLostException(e);
}
}
@Override
synchronized public void executeInstruction(int instruction)
throws ConnectionLostException {
checkState();
try {
ioio_.protocol_.icspSix(instruction);
} catch (IOException e) {
throw new ConnectionLostException(e);
}
}
@Override
synchronized public void readVisi() throws ConnectionLostException,
InterruptedException {
checkState();
while (rxRemaining_ < 2 && state_ == State.OPEN) {
wait();
}
checkState();
rxRemaining_ -= 2;
try {
ioio_.protocol_.icspRegout();
} catch (IOException e) {
throw new ConnectionLostException(e);
}
}
@Override
synchronized public void close() {
super.close();
ioio_.closeIcsp();
}
@Override
public synchronized void disconnected() {
super.disconnected();
notifyAll();
}
private static int byteToInt(byte b) {
return ((int) b) & 0xFF;
}
@Override
public synchronized int waitVisiResult() throws ConnectionLostException,
InterruptedException {
checkState();
while (resultQueue_.isEmpty() && state_ == State.OPEN) {
wait();
}
checkState();
return resultQueue_.remove();
}
}

View File

@@ -0,0 +1,109 @@
package ioio.lib.impl;
import ioio.lib.api.PulseInput;
import ioio.lib.api.exception.ConnectionLostException;
import ioio.lib.impl.IncomingState.DataModuleListener;
import java.util.LinkedList;
import java.util.Queue;
public class IncapImpl extends AbstractPin implements DataModuleListener,
PulseInput {
private static final int MAX_QUEUE_LEN = 32;
private final PulseMode mode_;
private final int incapNum_;
private long lastDuration_;
private final float timeBase_;
private final boolean doublePrecision_;
private boolean valid_ = false;
// TODO: a fixed-size array would have been much better than a linked list.
private Queue<Long> pulseQueue_ = new LinkedList<Long>();
public IncapImpl(IOIOImpl ioio, PulseMode mode, int incapNum, int pin,
int clockRate, int scale, boolean doublePrecision)
throws ConnectionLostException {
super(ioio, pin);
mode_ = mode;
incapNum_ = incapNum;
timeBase_ = 1.0f / (scale * clockRate);
doublePrecision_ = doublePrecision;
}
@Override
public float getFrequency() throws InterruptedException,
ConnectionLostException {
if (mode_ != PulseMode.FREQ && mode_ != PulseMode.FREQ_SCALE_4
&& mode_ != PulseMode.FREQ_SCALE_16) {
throw new IllegalStateException(
"Cannot query frequency when module was not opened in frequency mode.");
}
return 1.0f / getDuration();
}
@Override
public synchronized float getDuration() throws InterruptedException,
ConnectionLostException {
checkState();
while (!valid_) {
wait();
checkState();
}
return timeBase_ * lastDuration_;
}
@Override
public synchronized float waitPulseGetDuration()
throws InterruptedException, ConnectionLostException {
if (mode_ != PulseMode.POSITIVE && mode_ != PulseMode.NEGATIVE) {
throw new IllegalStateException(
"Cannot wait for pulse when module was not opened in pulse mode.");
}
checkState();
while (pulseQueue_.isEmpty() && state_ == State.OPEN) {
wait();
}
checkState();
return timeBase_ * pulseQueue_.remove();
}
@Override
public synchronized void dataReceived(byte[] data, int size) {
lastDuration_ = ByteArrayToLong(data, size);
if (pulseQueue_.size() == MAX_QUEUE_LEN) {
pulseQueue_.remove();
}
pulseQueue_.add(lastDuration_);
valid_ = true;
notifyAll();
}
private static long ByteArrayToLong(byte[] data, int size) {
long result = 0;
int i = size;
while (i-- > 0) {
result <<= 8;
result |= ((int) data[i]) & 0xFF;
}
if (result == 0) {
result = 1 << (size * 8);
}
return result;
}
@Override
public synchronized void reportAdditionalBuffer(int bytesToAdd) {
}
@Override
public synchronized void close() {
ioio_.closeIncap(incapNum_, doublePrecision_);
super.close();
}
@Override
public synchronized void disconnected() {
notifyAll();
super.disconnected();
}
}

View File

@@ -0,0 +1,460 @@
/*
* 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.exception.ConnectionLostException;
import ioio.lib.impl.IOIOProtocol.IncomingHandler;
import java.util.HashSet;
import java.util.Queue;
import java.util.Set;
import java.util.concurrent.ConcurrentLinkedQueue;
import android.util.Log;
public class IncomingState implements IncomingHandler {
enum ConnectionState {
INIT, ESTABLISHED, CONNECTED, DISCONNECTED, UNSUPPORTED_IID
}
interface InputPinListener {
void setValue(int value);
}
interface DisconnectListener {
void disconnected();
}
interface DataModuleListener {
void dataReceived(byte[] data, int size);
void reportAdditionalBuffer(int bytesToAdd);
}
class InputPinState {
private Queue<InputPinListener> listeners_ = new ConcurrentLinkedQueue<InputPinListener>();
private boolean currentOpen_ = false;
void pushListener(InputPinListener listener) {
listeners_.add(listener);
}
void closeCurrentListener() {
if (currentOpen_) {
currentOpen_ = false;
listeners_.remove();
}
}
void openNextListener() {
assert (!listeners_.isEmpty());
if (!currentOpen_) {
currentOpen_ = true;
}
}
void setValue(int v) {
assert (currentOpen_);
listeners_.peek().setValue(v);
}
}
class DataModuleState {
private Queue<DataModuleListener> listeners_ = new ConcurrentLinkedQueue<IncomingState.DataModuleListener>();
private boolean currentOpen_ = false;
void pushListener(DataModuleListener listener) {
listeners_.add(listener);
}
void closeCurrentListener() {
if (currentOpen_) {
currentOpen_ = false;
listeners_.remove();
}
}
void openNextListener() {
assert (!listeners_.isEmpty());
if (!currentOpen_) {
currentOpen_ = true;
}
}
void dataReceived(byte[] data, int size) {
assert (currentOpen_);
listeners_.peek().dataReceived(data, size);
}
public void reportAdditionalBuffer(int bytesRemaining) {
assert (currentOpen_);
listeners_.peek().reportAdditionalBuffer(bytesRemaining);
}
}
private final InputPinState[] intputPinStates_ = new InputPinState[Constants.NUM_PINS];
private final DataModuleState[] uartStates_ = new DataModuleState[Constants.NUM_UART_MODULES];
private final DataModuleState[] twiStates_ = new DataModuleState[Constants.NUM_TWI_MODULES];
private final DataModuleState[] spiStates_ = new DataModuleState[Constants.NUM_SPI_MODULES];
private final DataModuleState[] incapStates_ = new DataModuleState[2
* Constants.INCAP_MODULES_DOUBLE.length
+ Constants.INCAP_MODULES_SINGLE.length];
private final DataModuleState icspState_ = new DataModuleState();
private final Set<DisconnectListener> disconnectListeners_ = new HashSet<IncomingState.DisconnectListener>();
private ConnectionState connection_ = ConnectionState.INIT;
public String hardwareId_;
public String bootloaderId_;
public String firmwareId_;
public IncomingState() {
for (int i = 0; i < intputPinStates_.length; ++i) {
intputPinStates_[i] = new InputPinState();
}
for (int i = 0; i < uartStates_.length; ++i) {
uartStates_[i] = new DataModuleState();
}
for (int i = 0; i < twiStates_.length; ++i) {
twiStates_[i] = new DataModuleState();
}
for (int i = 0; i < spiStates_.length; ++i) {
spiStates_[i] = new DataModuleState();
}
for (int i = 0; i < incapStates_.length; ++i) {
incapStates_[i] = new DataModuleState();
}
}
synchronized public void waitConnectionEstablished()
throws InterruptedException, ConnectionLostException {
while (connection_ == ConnectionState.INIT) {
wait();
}
if (connection_ == ConnectionState.DISCONNECTED) {
throw new ConnectionLostException();
}
}
synchronized public boolean waitForInterfaceSupport()
throws InterruptedException, ConnectionLostException {
if (connection_ == ConnectionState.INIT) {
throw new IllegalStateException(
"Have to connect before waiting for interface support");
}
while (connection_ == ConnectionState.ESTABLISHED) {
wait();
}
if (connection_ == ConnectionState.DISCONNECTED) {
throw new ConnectionLostException();
}
return connection_ == ConnectionState.CONNECTED;
}
synchronized public void waitDisconnect() throws InterruptedException {
while (connection_ != ConnectionState.DISCONNECTED) {
wait();
}
}
public void addInputPinListener(int pin, InputPinListener listener) {
intputPinStates_[pin].pushListener(listener);
}
public void addUartListener(int uartNum, DataModuleListener listener) {
uartStates_[uartNum].pushListener(listener);
}
public void addTwiListener(int twiNum, DataModuleListener listener) {
twiStates_[twiNum].pushListener(listener);
}
public void addIncapListener(int incapNum, DataModuleListener listener) {
incapStates_[incapNum].pushListener(listener);
}
public void addIcspListener(DataModuleListener listener) {
icspState_.pushListener(listener);
}
public void addSpiListener(int spiNum, DataModuleListener listener) {
spiStates_[spiNum].pushListener(listener);
}
synchronized public void addDisconnectListener(DisconnectListener listener)
throws ConnectionLostException {
checkNotDisconnected();
disconnectListeners_.add(listener);
}
synchronized public void removeDisconnectListener(
DisconnectListener listener) {
if (connection_ != ConnectionState.DISCONNECTED) {
disconnectListeners_.remove(listener);
}
}
@Override
public void handleConnectionLost() {
// logMethod("handleConnectionLost");
synchronized (this) {
connection_ = ConnectionState.DISCONNECTED;
}
for (DisconnectListener listener : disconnectListeners_) {
listener.disconnected();
}
disconnectListeners_.clear();
synchronized (this) {
notifyAll();
}
}
@Override
public void handleSoftReset() {
// logMethod("handleSoftReset");
for (InputPinState pinState : intputPinStates_) {
pinState.closeCurrentListener();
}
for (DataModuleState uartState : uartStates_) {
uartState.closeCurrentListener();
}
for (DataModuleState twiState : twiStates_) {
twiState.closeCurrentListener();
}
for (DataModuleState spiState : spiStates_) {
spiState.closeCurrentListener();
}
for (DataModuleState incapState : incapStates_) {
incapState.closeCurrentListener();
}
icspState_.closeCurrentListener();
}
@Override
synchronized public void handleCheckInterfaceResponse(boolean supported) {
// logMethod("handleCheckInterfaceResponse", supported);
connection_ = supported ? ConnectionState.CONNECTED
: ConnectionState.UNSUPPORTED_IID;
notifyAll();
}
@Override
public void handleSetChangeNotify(int pin, boolean changeNotify) {
// logMethod("handleSetChangeNotify", pin, changeNotify);
if (changeNotify) {
intputPinStates_[pin].openNextListener();
} else {
intputPinStates_[pin].closeCurrentListener();
}
}
@Override
public void handleRegisterPeriodicDigitalSampling(int pin, int freqScale) {
// logMethod("handleRegisterPeriodicDigitalSampling", pin, freqScale);
assert (false);
}
@Override
public void handleAnalogPinStatus(int pin, boolean open) {
// logMethod("handleAnalogPinStatus", pin, open);
if (open) {
intputPinStates_[pin].openNextListener();
} else {
intputPinStates_[pin].closeCurrentListener();
}
}
@Override
public void handleUartData(int uartNum, int numBytes, byte[] data) {
// logMethod("handleUartData", uartNum, numBytes, data);
uartStates_[uartNum].dataReceived(data, numBytes);
}
@Override
public void handleUartOpen(int uartNum) {
// logMethod("handleUartOpen", uartNum);
uartStates_[uartNum].openNextListener();
}
@Override
public void handleUartClose(int uartNum) {
// logMethod("handleUartClose", uartNum);
uartStates_[uartNum].closeCurrentListener();
}
@Override
public void handleSpiOpen(int spiNum) {
// logMethod("handleSpiOpen", spiNum);
spiStates_[spiNum].openNextListener();
}
@Override
public void handleSpiClose(int spiNum) {
// logMethod("handleSpiClose", spiNum);
spiStates_[spiNum].closeCurrentListener();
}
@Override
public void handleI2cOpen(int i2cNum) {
// logMethod("handleI2cOpen", i2cNum);
twiStates_[i2cNum].openNextListener();
}
@Override
public void handleI2cClose(int i2cNum) {
// logMethod("handleI2cClose", i2cNum);
twiStates_[i2cNum].closeCurrentListener();
}
@Override
public void handleIcspOpen() {
// logMethod("handleIcspOpen");
icspState_.openNextListener();
}
@Override
public void handleIcspClose() {
// logMethod("handleIcspClose");
icspState_.closeCurrentListener();
}
@Override
public void handleEstablishConnection(byte[] hardwareId,
byte[] bootloaderId, byte[] firmwareId) {
hardwareId_ = new String(hardwareId);
bootloaderId_ = new String(bootloaderId);
firmwareId_ = new String(firmwareId);
Log.i("IncomingState", "IOIO Connection established. Hardware ID: "
+ hardwareId_ + " Bootloader ID: " + bootloaderId_
+ " Firmware ID: " + firmwareId_);
synchronized (this) {
connection_ = ConnectionState.ESTABLISHED;
notifyAll();
}
}
@Override
public void handleUartReportTxStatus(int uartNum, int bytesRemaining) {
// logMethod("handleUartReportTxStatus", uartNum, bytesRemaining);
uartStates_[uartNum].reportAdditionalBuffer(bytesRemaining);
}
@Override
public void handleI2cReportTxStatus(int i2cNum, int bytesRemaining) {
// logMethod("handleI2cReportTxStatus", i2cNum, bytesRemaining);
twiStates_[i2cNum].reportAdditionalBuffer(bytesRemaining);
}
@Override
public void handleSpiData(int spiNum, int ssPin, byte[] data, int dataBytes) {
// logMethod("handleSpiData", spiNum, ssPin, data, dataBytes);
spiStates_[spiNum].dataReceived(data, dataBytes);
}
@Override
public void handleIcspReportRxStatus(int bytesRemaining) {
// logMethod("handleIcspReportRxStatus", bytesRemaining);
icspState_.reportAdditionalBuffer(bytesRemaining);
}
@Override
public void handleReportDigitalInStatus(int pin, boolean level) {
// logMethod("handleReportDigitalInStatus", pin, level);
intputPinStates_[pin].setValue(level ? 1 : 0);
}
@Override
public void handleReportPeriodicDigitalInStatus(int frameNum,
boolean[] values) {
// logMethod("handleReportPeriodicDigitalInStatus", frameNum, values);
}
@Override
public void handleReportAnalogInStatus(int pins[], int values[]) {
// logMethod("handleReportAnalogInStatus", pins, values);
for (int i = 0; i < pins.length; ++i) {
intputPinStates_[pins[i]].setValue(values[i]);
}
}
@Override
public void handleSpiReportTxStatus(int spiNum, int bytesRemaining) {
// logMethod("handleSpiReportTxStatus", spiNum, bytesRemaining);
spiStates_[spiNum].reportAdditionalBuffer(bytesRemaining);
}
@Override
public void handleI2cResult(int i2cNum, int size, byte[] data) {
// logMethod("handleI2cResult", i2cNum, size, data);
twiStates_[i2cNum].dataReceived(data, size);
}
@Override
public void handleIncapReport(int incapNum, int size, byte[] data) {
// logMethod("handleIncapReport", incapNum, size, data);
incapStates_[incapNum].dataReceived(data, size);
}
@Override
public void handleIncapClose(int incapNum) {
// logMethod("handleIncapClose", incapNum);
incapStates_[incapNum].closeCurrentListener();
}
@Override
public void handleIncapOpen(int incapNum) {
// logMethod("handleIncapOpen", incapNum);
incapStates_[incapNum].openNextListener();
}
@Override
public void handleIcspResult(int size, byte[] data) {
// logMethod("handleIcspResult", size, data);
icspState_.dataReceived(data, size);
}
private void checkNotDisconnected() throws ConnectionLostException {
if (connection_ == ConnectionState.DISCONNECTED) {
throw new ConnectionLostException();
}
}
// private void logMethod(String name, Object... args) {
// StringBuffer msg = new StringBuffer(name);
// msg.append('(');
// for (int i = 0; i < args.length; ++i) {
// if (i != 0) {
// msg.append(", ");
// }
// msg.append(args[i]);
// }
// msg.append(')');
//
// Log.v("IncomingState", msg.toString());
// }
}

View File

@@ -0,0 +1,106 @@
/*
* 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.exception.OutOfResourceException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.TreeSet;
/**
* Utility to allocate and assign unique module ids.
* A module id is requested via {@link #allocateModule()}
* and released via {@link #releaseModule(int)}.
*
* @author birmiwal
*/
public class ModuleAllocator {
private final Set<Integer> availableModuleIds_;
private final Set<Integer> allocatedModuleIds_;
private final String name_;
public ModuleAllocator(Collection<Integer> availableModuleIds, String name) {
this.availableModuleIds_ = new TreeSet<Integer>(availableModuleIds);
allocatedModuleIds_ = new HashSet<Integer>();
name_ = name;
}
public ModuleAllocator(int[] availableModuleIds, String name) {
this(getList(availableModuleIds), name);
}
public ModuleAllocator(int maxModules, String name) {
this(getList(maxModules), name);
}
private static Collection<Integer> getList(int maxModules) {
List<Integer> availableModuleIds = new ArrayList<Integer>();
for (int i = 0; i < maxModules; i++) {
availableModuleIds.add(i);
}
return availableModuleIds;
}
private static Collection<Integer> getList(int[] array) {
List<Integer> availableModuleIds = new ArrayList<Integer>(array.length);
for (int i : array) {
availableModuleIds.add(i);
}
return availableModuleIds;
}
/**
* @return a module id that was allocated, or {@code null} if nothing was available
*/
public synchronized Integer allocateModule() {
if (availableModuleIds_.isEmpty()) {
throw new OutOfResourceException("No more resources of the requested type: " + name_);
}
Integer moduleId = availableModuleIds_.iterator().next();
availableModuleIds_.remove(moduleId);
allocatedModuleIds_.add(moduleId);
return moduleId;
}
/**
* @param moduleId the moduleId to be released; throws {@link IllegalArgumentException} if
* a moduleId is re-returned, or an invalid moduleId is provided
*/
public synchronized void releaseModule(int moduleId) {
if (!allocatedModuleIds_.contains(moduleId)) {
throw new IllegalArgumentException("moduleId: " + moduleId+ "; not yet allocated");
}
availableModuleIds_.add(moduleId);
allocatedModuleIds_.remove(moduleId);
}
}

View File

@@ -0,0 +1,76 @@
/*
* 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;
public class PinFunctionMap {
private static final boolean[] PERIPHERAL_OUT = new boolean[] { true,
false, false, true, true, true, true, true, false, false, true,
true, true, true, true, false, false, false, false, false, false,
false, false, false, false, false, false, true, true, true, true,
true, true, false, true, true, true, true, true, true, true, false,
false, false, false, true, true, true, true };
private static final boolean[] PERIPHERAL_IN = new boolean[] { true,
false, false, true, true, true, true, true, false, true, true,
true, true, true, true, false, false, false, false, false, false,
false, false, false, false, false, false, true, true, true, true,
true, true, false, true, true, true, true, true, true, true, false,
false, false, false, true, true, true, true };
static void checkSupportsAnalogInput(int pin) {
checkValidPin(pin);
if (pin < 31 || pin > 46) {
throw new IllegalArgumentException("Pin " + pin
+ " does not support analog input");
}
}
static void checkSupportsPeripheralInput(int pin) {
checkValidPin(pin);
if (!PERIPHERAL_IN[pin]) {
throw new IllegalArgumentException("Pin " + pin
+ " does not support peripheral input");
}
}
static void checkSupportsPeripheralOutput(int pin) {
checkValidPin(pin);
if (!PERIPHERAL_OUT[pin]) {
throw new IllegalArgumentException("Pin " + pin
+ " does not support peripheral output");
}
}
static void checkValidPin(int pin) {
if (pin < 0 || pin > 48) {
throw new IllegalArgumentException("Illegal pin: " + pin);
}
}
}

View File

@@ -0,0 +1,101 @@
/*
* 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.PwmOutput;
import ioio.lib.api.exception.ConnectionLostException;
import java.io.IOException;
public class PwmImpl extends AbstractResource implements PwmOutput {
private final int pwmNum_;
private final int pinNum_;
private final float baseUs_;
private final int period_;
public PwmImpl(IOIOImpl ioio, int pinNum, int pwmNum, int period,
float baseUs) throws ConnectionLostException {
super(ioio);
pwmNum_ = pwmNum;
pinNum_ = pinNum;
baseUs_ = baseUs;
period_ = period;
}
@Override
public synchronized void close() {
super.close();
ioio_.closePwm(pwmNum_);
ioio_.closePin(pinNum_);
}
@Override
public void setDutyCycle(float dutyCycle) throws ConnectionLostException {
assert (dutyCycle <= 1 && dutyCycle >= 0);
setPulseWidthInClocks(period_ * dutyCycle);
}
@Override
public void setPulseWidth(int pulseWidthUs) throws ConnectionLostException {
setPulseWidth((float) pulseWidthUs);
}
@Override
public void setPulseWidth(float pulseWidthUs)
throws ConnectionLostException {
assert (pulseWidthUs >= 0);
float p = pulseWidthUs / baseUs_;
setPulseWidthInClocks(p);
}
synchronized private void setPulseWidthInClocks(float p)
throws ConnectionLostException {
checkState();
if (p > period_) {
p = period_;
}
int pw;
int fraction;
p -= 1; // period parameter is one less than the actual period length
// yes, there is 0 and then 2 (no 1) - this is not a bug, that
// is how the hardware PWM module works.
if (p < 1) {
pw = 0;
fraction = 0;
} else {
pw = (int) p;
fraction = ((int) p * 4) & 0x03;
}
try {
ioio_.protocol_.setPwmDutyCycle(pwmNum_, pw, fraction);
} catch (IOException e) {
throw new ConnectionLostException(e);
}
}
}

View File

@@ -0,0 +1,79 @@
/*
* 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 java.io.IOException;
import java.io.InputStream;
import java.util.Queue;
import java.util.concurrent.ArrayBlockingQueue;
import android.util.Log;
public class QueueInputStream extends InputStream {
private final Queue<Byte> queue_ = new ArrayBlockingQueue<Byte>(
Constants.BUFFER_SIZE);
private boolean closed_ = false;
@Override
synchronized public int read() throws IOException {
try {
while (!closed_ && queue_.isEmpty()) {
wait();
}
if (closed_) {
throw new IOException("Stream has been closed");
}
return ((int) queue_.remove()) & 0xFF;
} catch (InterruptedException e) {
throw new IOException("Interrupted");
}
}
synchronized public void write(byte[] data, int size) {
for (int i = 0; i < size; ++i) {
if (queue_.size() == Constants.BUFFER_SIZE) {
Log.e("QueueInputStream", "Buffer overflow, discarding data");
break;
}
queue_.add(data[i]);
}
notifyAll();
}
@Override
synchronized public int available() throws IOException {
return queue_.size();
}
@Override
synchronized public void close() {
closed_ = true;
}
}

View File

@@ -0,0 +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.impl;
import ioio.lib.api.IOIOConnection;
import ioio.lib.api.exception.ConnectionLostException;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.SocketException;
import android.util.Log;
public class SocketIOIOConnection implements IOIOConnection {
private final int port_;
private ServerSocket server_ = null;
private Socket socket_ = null;
private boolean disconnect_ = false;
private boolean server_owned_by_connect_ = true;
private boolean socket_owned_by_connect_ = true;
public SocketIOIOConnection(Integer port) {
port_ = port;
}
@Override
public void waitForConnect() throws ConnectionLostException {
try {
synchronized (this) {
if (disconnect_) {
throw new ConnectionLostException();
}
Log.d("SocketIOIOConnection", "Creating server socket");
server_ = new ServerSocket(port_);
server_owned_by_connect_ = false;
}
Log.d("SocketIOIOConnection", "Waiting for TCP connection");
socket_ = server_.accept();
Log.d("SocketIOIOConnection", "TCP connected");
synchronized (this) {
if (disconnect_) {
socket_.close();
throw new ConnectionLostException();
}
socket_owned_by_connect_ = false;
}
} catch (IOException e) {
synchronized (this) {
disconnect_ = true;
if (server_owned_by_connect_ && server_ != null) {
try {
server_.close();
} catch (IOException e1) {
Log.e("SocketIOIOConnection", "Unexpected exception", e1);
}
}
if (socket_owned_by_connect_ && socket_ != null) {
try {
socket_.close();
} catch (IOException e1) {
Log.e("SocketIOIOConnection", "Unexpected exception", e1);
}
}
if (e instanceof SocketException && e.getMessage().equals("Permission denied")) {
Log.e("SocketIOIOConnection", "Did you forget to declare uses-permission of android.permission.INTERNET?");
}
throw new ConnectionLostException(e);
}
}
}
@Override
synchronized public void disconnect() {
if (disconnect_) {
return;
}
Log.d("SocketIOIOConnection", "Client initiated disconnect");
disconnect_ = true;
if (!server_owned_by_connect_) {
try {
server_.close();
} catch (IOException e1) {
Log.e("SocketIOIOConnection", "Unexpected exception", e1);
}
}
if (!socket_owned_by_connect_) {
try {
socket_.shutdownOutput();
} catch (IOException e1) {
}
}
}
@Override
public InputStream getInputStream() throws ConnectionLostException {
try {
return socket_.getInputStream();
} catch (IOException e) {
throw new ConnectionLostException(e);
}
}
@Override
public OutputStream getOutputStream() throws ConnectionLostException {
try {
return socket_.getOutputStream();
} catch (IOException e) {
throw new ConnectionLostException(e);
}
}
}

View File

@@ -0,0 +1,198 @@
/*
* 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.SpiMaster;
import ioio.lib.api.exception.ConnectionLostException;
import ioio.lib.impl.FlowControlledPacketSender.Packet;
import ioio.lib.impl.FlowControlledPacketSender.Sender;
import ioio.lib.impl.IncomingState.DataModuleListener;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.Queue;
import java.util.concurrent.ConcurrentLinkedQueue;
import android.util.Log;
public class SpiMasterImpl extends AbstractResource implements SpiMaster,
DataModuleListener, Sender {
public class SpiResult implements Result {
boolean ready_;
final byte[] data_;
SpiResult(byte[] data) {
data_ = data;
}
@Override
public synchronized void waitReady() throws ConnectionLostException,
InterruptedException {
while (!ready_ && state_ != State.DISCONNECTED) {
wait();
}
checkState();
}
}
class OutgoingPacket implements Packet {
int writeSize_;
byte[] writeData_;
int ssPin_;
int readSize_;
int totalSize_;
@Override
public int getSize() {
return writeSize_ + 4;
}
}
private final Queue<SpiResult> pendingRequests_ = new ConcurrentLinkedQueue<SpiMasterImpl.SpiResult>();
private final FlowControlledPacketSender outgoing_ = new FlowControlledPacketSender(
this);
private final int spiNum_;
private final Map<Integer, Integer> ssPinToIndex_;
private final int[] indexToSsPin_;
private final int mosiPinNum_;
private final int misoPinNum_;
private final int clkPinNum_;
SpiMasterImpl(IOIOImpl ioio, int spiNum, int mosiPinNum, int misoPinNum,
int clkPinNum, int[] ssPins) throws ConnectionLostException {
super(ioio);
spiNum_ = spiNum;
mosiPinNum_ = mosiPinNum;
misoPinNum_ = misoPinNum;
clkPinNum_ = clkPinNum;
indexToSsPin_ = ssPins.clone();
ssPinToIndex_ = new HashMap<Integer, Integer>(ssPins.length);
for (int i = 0; i < ssPins.length; ++i) {
ssPinToIndex_.put(ssPins[i], i);
}
}
@Override
synchronized public void disconnected() {
super.disconnected();
outgoing_.kill();
for (SpiResult tr : pendingRequests_) {
synchronized (tr) {
tr.notify();
}
}
}
@Override
public void writeRead(int slave, byte[] writeData, int writeSize,
int totalSize, byte[] readData, int readSize)
throws ConnectionLostException, InterruptedException {
Result result = writeReadAsync(slave, writeData, writeSize,
totalSize, readData, readSize);
result.waitReady();
}
@Override
public SpiResult writeReadAsync(int slave, byte[] writeData,
int writeSize, int totalSize, byte[] readData, int readSize)
throws ConnectionLostException {
checkState();
SpiResult result = new SpiResult(readData);
OutgoingPacket p = new OutgoingPacket();
p.writeSize_ = writeSize;
p.writeData_ = writeData;
p.readSize_ = readSize;
p.ssPin_ = indexToSsPin_[slave];
p.totalSize_ = totalSize;
if (p.readSize_ > 0) {
synchronized (this) {
pendingRequests_.add(result);
}
} else {
result.ready_ = true;
}
try {
outgoing_.write(p);
} catch (IOException e) {
Log.e("SpiMasterImpl", "Exception caught", e);
}
return result;
}
@Override
public void writeRead(byte[] writeData, int writeSize, int totalSize,
byte[] readData, int readSize) throws ConnectionLostException,
InterruptedException {
writeRead(0, writeData, writeSize, totalSize, readData, readSize);
}
@Override
public void dataReceived(byte[] data, int size) {
SpiResult result = pendingRequests_.remove();
synchronized (result) {
result.ready_ = true;
System.arraycopy(data, 0, result.data_, 0, size);
result.notify();
}
}
@Override
public void reportAdditionalBuffer(int bytesRemaining) {
outgoing_.readyToSend(bytesRemaining);
}
@Override
synchronized public void close() {
super.close();
outgoing_.close();
ioio_.closeSpi(spiNum_);
ioio_.closePin(mosiPinNum_);
ioio_.closePin(misoPinNum_);
ioio_.closePin(clkPinNum_);
for (int pin : indexToSsPin_) {
ioio_.closePin(pin);
}
}
@Override
public void send(Packet packet) {
OutgoingPacket p = (OutgoingPacket) packet;
try {
ioio_.protocol_.spiMasterRequest(spiNum_, p.ssPin_, p.writeData_,
p.writeSize_, p.totalSize_, p.readSize_);
} catch (IOException e) {
Log.e("SpiImpl", "Caught exception", e);
}
}
}

View File

@@ -0,0 +1,169 @@
/*
* 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.TwiMaster;
import ioio.lib.api.exception.ConnectionLostException;
import ioio.lib.impl.FlowControlledPacketSender.Packet;
import ioio.lib.impl.FlowControlledPacketSender.Sender;
import ioio.lib.impl.IncomingState.DataModuleListener;
import java.io.IOException;
import java.util.Queue;
import java.util.concurrent.ConcurrentLinkedQueue;
import android.util.Log;
public class TwiMasterImpl extends AbstractResource implements TwiMaster,
DataModuleListener, Sender {
class TwiResult implements Result {
boolean ready_ = false;
boolean success_;
final byte[] data_;
public TwiResult(byte[] data) {
data_ = data;
}
@Override
public synchronized boolean waitReady() throws ConnectionLostException,
InterruptedException {
while (!ready_ && state_ != State.DISCONNECTED) {
wait();
}
checkState();
return success_;
}
}
class OutgoingPacket implements Packet {
int writeSize_;
byte[] writeData_;
boolean tenBitAddr_;
int addr_;
int readSize_;
@Override
public int getSize() {
return writeSize_ + 4;
}
}
private final Queue<TwiResult> pendingRequests_ = new ConcurrentLinkedQueue<TwiMasterImpl.TwiResult>();
private final FlowControlledPacketSender outgoing_ = new FlowControlledPacketSender(
this);
private final int twiNum_;
TwiMasterImpl(IOIOImpl ioio, int twiNum) throws ConnectionLostException {
super(ioio);
twiNum_ = twiNum;
}
@Override
synchronized public void disconnected() {
super.disconnected();
outgoing_.kill();
for (TwiResult tr : pendingRequests_) {
synchronized (tr) {
tr.notify();
}
}
}
@Override
public boolean writeRead(int address, boolean tenBitAddr, byte[] writeData,
int writeSize, byte[] readData, int readSize)
throws ConnectionLostException, InterruptedException {
Result result = writeReadAsync(address, tenBitAddr, writeData,
writeSize, readData, readSize);
return result.waitReady();
}
@Override
public Result writeReadAsync(int address, boolean tenBitAddr,
byte[] writeData, int writeSize, byte[] readData, int readSize)
throws ConnectionLostException {
checkState();
TwiResult result = new TwiResult(readData);
OutgoingPacket p = new OutgoingPacket();
p.writeSize_ = writeSize;
p.writeData_ = writeData;
p.tenBitAddr_ = tenBitAddr;
p.readSize_ = readSize;
p.addr_ = address;
synchronized (this) {
pendingRequests_.add(result);
try {
outgoing_.write(p);
} catch (IOException e) {
Log.e("SpiMasterImpl", "Exception caught", e);
}
}
return result;
}
@Override
public void dataReceived(byte[] data, int size) {
TwiResult result = pendingRequests_.remove();
synchronized (result) {
result.ready_ = true;
result.success_ = (size != 0xFF);
if (result.success_) {
System.arraycopy(data, 0, result.data_, 0, size);
}
result.notify();
}
}
@Override
public void reportAdditionalBuffer(int bytesRemaining) {
outgoing_.readyToSend(bytesRemaining);
}
@Override
synchronized public void close() {
super.close();
outgoing_.close();
ioio_.closeTwi(twiNum_);
}
@Override
public void send(Packet packet) {
OutgoingPacket p = (OutgoingPacket) packet;
try {
ioio_.protocol_.i2cWriteRead(twiNum_, p.tenBitAddr_, p.addr_,
p.writeSize_, p.readSize_, p.writeData_);
} catch (IOException e) {
Log.e("TwiImpl", "Caught exception", e);
}
}
}

View File

@@ -0,0 +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.impl;
import ioio.lib.api.IOIO;
import ioio.lib.api.Uart;
import ioio.lib.api.exception.ConnectionLostException;
import ioio.lib.impl.FlowControlledOutputStream.Sender;
import ioio.lib.impl.IncomingState.DataModuleListener;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import android.util.Log;
public class UartImpl extends AbstractResource implements DataModuleListener, Sender, Uart {
private static final int MAX_PACKET = 64;
private final int uartNum_;
private final int rxPinNum_;
private final int txPinNum_;
private final FlowControlledOutputStream outgoing_ = new FlowControlledOutputStream(this, MAX_PACKET);
private final QueueInputStream incoming_ = new QueueInputStream();
public UartImpl(IOIOImpl ioio, int txPin, int rxPin, int uartNum) throws ConnectionLostException {
super(ioio);
uartNum_ = uartNum;
rxPinNum_ = rxPin;
txPinNum_ = txPin;
}
@Override
public void dataReceived(byte[] data, int size) {
incoming_.write(data, size);
}
@Override
public void send(byte[] data, int size) {
try {
ioio_.protocol_.uartData(uartNum_, size, data);
} catch (IOException e) {
Log.e("UartImpl", e.getMessage());
}
}
@Override
synchronized public void close() {
super.close();
incoming_.close();
outgoing_.close();
ioio_.closeUart(uartNum_);
if (rxPinNum_ != IOIO.INVALID_PIN) {
ioio_.closePin(rxPinNum_);
}
if (txPinNum_ != IOIO.INVALID_PIN) {
ioio_.closePin(txPinNum_);
}
}
@Override
synchronized public void disconnected() {
super.disconnected();
outgoing_.kill();
}
@Override
public InputStream getInputStream() {
return incoming_;
}
@Override
public OutputStream getOutputStream() {
return outgoing_;
}
@Override
public void reportAdditionalBuffer(int bytesRemaining) {
outgoing_.readyToSend(bytesRemaining);
}
}

View File

@@ -0,0 +1,295 @@
package ioio.lib.util;
import ioio.lib.api.IOIO;
import ioio.lib.api.IOIOFactory;
import ioio.lib.api.exception.ConnectionLostException;
import ioio.lib.api.exception.IncompatibilityException;
import ioio.lib.util.IOIOConnectionDiscovery.IOIOConnectionSpec;
import java.util.Collection;
import java.util.LinkedList;
import android.app.Activity;
import android.os.Looper;
import android.util.Log;
/**
* A convenience class for easy creation of IOIO-based applications.
*
* It is used by creating a concrete Activity in your application, which extends
* this class. This class then takes care of proper creation and abortion of the
* IOIO connection and of a dedicated thread for IOIO communication.
*
* In the basic usage the client should extend this class and implement
* {@link #createIOIOThread()}, which should return an implementation of the
* {@link IOIOThread} abstract class. In this implementation, the client
* implements the {@link IOIOThread#setup()} method, which gets called as soon
* as communication with the IOIO is established, and the {@link IOIOThread
* #loop()} method, which gets called repetitively as long as the IOIO is
* connected. Both methods should access the {@link IOIOThread#ioio_} field for
* controlling the IOIO.
*
* In addition, the {@link IOIOThread#disconnected()} method may be overridden
* in order to execute logic as soon as a disconnection occurs for whichever
* reason. The {@link IOIOThread#incompatible()} method may be overridden in
* order to take action in case where a IOIO whose firmware is incompatible with
* the IOIOLib version that application is built with.
*
* In a more advanced use case, more than one IOIO is available. In this case, a
* thread will be created for each IOIO, whose semantics are as defined above.
* If the client needs to be able to distinguish between them, it is possible to
* override {@link #createIOIOThread(String, Object[])} instead of
* {@link #createIOIOThread()}. The first argument provided will contain the
* connection class name, such as ioio.lib.impl.SocketIOIOConnection for a
* connection established over a TCP socket (which is used over ADB). The second
* argument will contain information specific to the connection type. For
* example, in the case of SocketIOIOConnection, the array will contain an
* {@link Integer} representing the local port number.
*
*/
public abstract class AbstractIOIOActivity extends Activity {
private static final String TAG = "AbstractIOIOActivity";
private IOIOConnectionSpec currentSpec_;
private Collection<IOIOThread> threads_ = new LinkedList<IOIOThread>();
/**
* Subclasses should call this method from their own onResume() if
* overloaded. It takes care of connecting with the IOIO.
*/
@Override
protected void onResume() {
super.onResume();
createAllThreads();
startAllThreads();
}
/**
* Subclasses should call this method from their own onPause() if
* overloaded. It takes care of disconnecting from the IOIO.
*/
@Override
protected void onPause() {
super.onPause();
abortAllThreads();
try {
joinAllThreads();
} catch (InterruptedException e) {
}
}
/**
* Subclasses should implement this method by returning a concrete subclass
* of {@link IOIOThread}. <code>null</code> may be returned if the client
* is not interested to connect a thread for this IOIO. In multi-IOIO
* scenarios, where you want to identify which IOIO the thread is for,
* consider using {@link #createIOIOThread()} instead.
*
* @return An implementation of {@link IOIOThread}, or <code>null</code> to
* skip.
*/
protected IOIOThread createIOIOThread() {
return null;
}
/**
* Subclasses should implement this method by returning a concrete subclass
* of {@link IOIOThread}. This overload is useful in multi-IOIO scenarios,
* where you want to identify which IOIO the thread is for. The provided
* arguments should provide enough information to be unique per connection.
* <code>null</code> may be returned if the client is not interested to
* connect a thread for this IOIO. This can be used in order to filter out
* unwanted connections, for example if the application is only intended for
* wireless connection, any wired connection attempts may be rejected, thus
* saving resources used for listening for incoming wired connections.
*
* @param connectionClass
* The fully-qualified name of the connection class used to
* connect to the IOIO.
* @param connectionArgs
* A list of arguments passed to the constructor of the
* connection class. Should provide information that enables
* distinguishing between different IOIO instances using the same
* connection class.
*
* @return An implementation of {@link IOIOThread}, or <code>null</code> to
* skip.
*/
protected IOIOThread createIOIOThread(String connectionClass,
Object[] connectionArgs) {
return createIOIOThread();
}
/**
* An abstract class, which facilitates a thread dedicated for communication
* with a single physical IOIO device.
*/
protected abstract class IOIOThread extends Thread {
/** Subclasses should use this field for controlling the IOIO. */
protected IOIO ioio_;
private boolean abort_ = false;
private boolean connected_ = true;
private final IOIOConnectionSpec spec_ = currentSpec_;
/**
* Subclasses should override this method for performing operations to
* be done once as soon as IOIO communication is established. Typically,
* this will include opening pins and modules using the openXXX()
* methods of the {@link #ioio_} field.
*/
protected void setup() throws ConnectionLostException,
InterruptedException {
}
/**
* Subclasses should override this method for performing operations to
* be done repetitively as long as IOIO communication persists.
* Typically, this will be the main logic of the application, processing
* inputs and producing outputs.
*/
protected void loop() throws ConnectionLostException,
InterruptedException {
sleep(100000);
}
/**
* Subclasses should override this method for performing operations to
* be done once as soon as IOIO communication is lost or closed.
* Typically, this will include GUI changes corresponding to the change.
* This method will only be called if setup() has been called. The
* {@link #ioio_} member must not be used from within this method.
*/
protected void disconnected() throws InterruptedException {
}
/**
* Subclasses should override this method for performing operations to
* be done if an incompatible IOIO firmware is detected. The
* {@link #ioio_} member must not be used from within this method. This
* method will only be called once, until a compatible IOIO is connected
* (i.e. {@link #setup()} gets called).
*/
protected void incompatible() {
}
/** Not relevant to subclasses. */
@Override
public final void run() {
super.run();
Looper.prepare();
while (true) {
try {
synchronized (this) {
if (abort_) {
break;
}
ioio_ = IOIOFactory.create(spec_.className, spec_.args);
}
ioio_.waitForConnect();
connected_ = true;
setup();
while (!abort_) {
loop();
}
ioio_.disconnect();
} catch (ConnectionLostException e) {
if (abort_) {
break;
}
} catch (InterruptedException e) {
ioio_.disconnect();
break;
} catch (IncompatibilityException e) {
Log.e(TAG, "Incompatible IOIO firmware", e);
incompatible();
// nothing to do - just wait until physical disconnection
try {
ioio_.waitForDisconnect();
} catch (InterruptedException e1) {
ioio_.disconnect();
}
} catch (Exception e) {
Log.e(TAG, "Unexpected exception caught", e);
ioio_.disconnect();
break;
} finally {
try {
if (ioio_ != null) {
ioio_.waitForDisconnect();
if (connected_) {
disconnected();
}
}
} catch (InterruptedException e) {
}
}
}
}
/** Not relevant to subclasses. */
public synchronized final void abort() {
abort_ = true;
if (ioio_ != null) {
ioio_.disconnect();
}
if (connected_) {
interrupt();
}
}
}
private void abortAllThreads() {
for (IOIOThread thread : threads_) {
thread.abort();
}
}
private void joinAllThreads() throws InterruptedException {
for (IOIOThread thread : threads_) {
thread.join();
}
}
private void createAllThreads() {
threads_.clear();
Collection<IOIOConnectionSpec> specs = getConnectionSpecs();
for (IOIOConnectionSpec spec : specs) {
currentSpec_ = spec;
IOIOThread thread = createIOIOThread(spec.className, spec.args);
if (thread != null) {
threads_.add(thread);
}
}
}
private void startAllThreads() {
for (IOIOThread thread : threads_) {
thread.start();
}
}
private Collection<IOIOConnectionSpec> getConnectionSpecs() {
Collection<IOIOConnectionSpec> result = new LinkedList<IOIOConnectionSpec>();
addConnectionSpecs("ioio.lib.util.SocketIOIOConnectionDiscovery",
result);
addConnectionSpecs(
"ioio.lib.bluetooth.BluetoothIOIOConnectionDiscovery", result);
return result;
}
private void addConnectionSpecs(String discoveryClassName,
Collection<IOIOConnectionSpec> result) {
try {
Class<?> cls = Class.forName(discoveryClassName);
IOIOConnectionDiscovery discovery = (IOIOConnectionDiscovery) cls
.newInstance();
discovery.getSpecs(result);
} catch (ClassNotFoundException e) {
Log.d(TAG, "Discovery class not found: " + discoveryClassName
+ ". Not adding.");
} catch (Exception e) {
Log.w(TAG,
"Exception caught while discovering connections - not adding connections of class "
+ discoveryClassName, e);
}
}
}

View File

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

View File

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