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