Skip to content

IOIOLib Core API

Ytai Ben-Tsvi edited this page Jul 11, 2012 · 2 revisions

#IOIOLib Core API

The IOIO Interface

The IOIO interface is the heart of the IOIOLib. An instance of this interface represents a physical IOIO board, and through its methods you can control its various functions, such as reading or writing values to individual physical pins.

Obtaining a IOIO Instance

The way to obtain an instance of the IOIO interface, which is ready to control a physical board depends on various factors, such as the type of application (e.g. Android Activity or PC Swing) and the connection type (e.g. USB, Bluetooth). In order to hide away the complexity involved, the IOIOLib library provides an application framework. Read more about it here. An alternative, and normally disrecommended way is desribed at the bottom of this page. For the remainder of this document, we assume an existing, connected IOIO instance.

Using the IOIO Interface

Once the IOIO is connected and you have a live IOIO instance, you can start using it (well, that's what you bought it for, probably)! Its various functions are normally accessed via sub-instances obtained from the openXYZ() methods. These sub-instances remain associated with the IOIO instance which created them throughout their lifetime. They all extend the Closeable interface, which simply means your can call close() on them. Calling close() will invalidate the instance on which it was called, and will free and resources (e.g. pins) it used for future use. For documentation on specific functions, please refer to:

Effects of a Disconnection

From the moment a disconnection occurs, whether due to a client-initiated disconnect (e.g. exiting the application) or due to a physical disconnection, the instance, as well as any other instances obtained from it, will throw a ConnectionLostException upon every call. A IOIO instance is one-time-use. This means that once a connection is lost, the instance is as good as dead. It cannot be recycled. The application framework will automatically create a new instance as soon as the connection is re-established.

Resets

There are two kinds of resets, soft and hard.

A soft reset means "return everything to its initial state". This includes closing all interfaces obtained from this IOIO instance, and in turn freeing all resources. All pins (save the stat LED) will become floating inputs. All modules will be powered off. These operations are done without dropping the connection with the IOIO, thus a soft reset is very fast. It is generally not a good practice to replace proper closing of sub-instances with a soft reset. However, under some circumstances, such as tests, this might make sense.

A soft reset is performed by calling:

ioio.softReset();

A hard reset is exactly like physically powering off the IOIO board and powering it back on. As a result, the connection with the IOIO will drop and the IOIO instance will become disconnected and unusable. The board will perform a full reboot, including going through the bootloader sequence, i.e. an attempt to update the board's firmware will be made. Hard reset is mostly useful for this very purpose - your application wants to initiate a firmware upgrade. In the future, applications (or IOIOLib) will be able to request an install of ad-hoc firmware on the board. A hard reset will then enable the board to pick up the new firmware and start executing it.

A hard reset is performed by calling:

ioio.hardReset();

Batching Operations

In some cases, your application uses a high rate of write operations to the IOIO. An example might be changing a bunch of digital outputs immediately one after the other to achieve a parallel-like interface. Doing these operations naively, will cause a message to be sent to the IOIO for every operation. Every such message incurs a certain latency and this latency adds up and may become significant for large amount of writes and latency-sensitive applications.

For that purpose, an optimization method is available in the IOIO interface, which enables grouping a number of such write operations into a single message that is sent to the IOIO, thus taking the latency hit only once per group rather than once per operation. This is strictly an advanced optimization and will not change functionality. It is recommended to use this technique only after everything works without it and improving latency is desired. Note that trying to group operations that block until response from the IOIO is obtained (such as SPI or TWI writeRead()) will hang your thread!

Grouping is achieved simply by surrounding your group of write operations with a

ioio.beginBatch()

and

ioio.endBatch()

calls. The former will cause the IOIO instance to delay all messages until the latter is called. Note that this is strictly a hint. The IOIO instance may decide to send a message nevertheless, if, for example, the buffered messages become too long. Also note that it is legal to nest such batch blocks. The messages to the IOIO will be delayed until the outermost block exits.

Take extra care about ending a batch cleanly in the presence of exceptions. Possibly, put it in a finally block immediately surrounding all the block contents, such as:

ioio.beginBatch();
try {
  pin1.write(false);
  pin2.write(true);
  ...
} finally {
  ioio.endBatch();
}

Appendix: Explicit Creation, Connection and Disconnection

Note: It very uncommon to have to create the IOIO instance yourself and explicitly control its connection and disconnection. It is highly recommended to use the IOIOLib Application Framework instead, which will take care of many delicate details required for creation of a robust application. If you don't really understand the inner workings of IOIOLib and are convinced that this is the best solution for you, it probably isn't!

Explicitly Creating a IOIO Instance and Establishing a Connection

In order to create an instance of IOIO over ADB/USB, you should use the IOIOFactory.create() method. Simply call:

IOIO ioio = IOIOFactory.create();

The call will return immediately, providing you with a valid instance. However, this instance is not yet usable, and any attempt to use it will throw an exception. A connection with the board must first be created, by calling:

ioio.waitForConnect();

This call will block until the board is powered, physically connected via USB and establishes communications with your application (if it doesn't, make sure you've got USB debugging turned on).

For creating a IOIO over a different connection type, use the overload of create(), which gets a IOIOConnection argument

Explicit Disconnection

In order to disconnect from the board (automatically resetting its state), or abort an on-going waitForConnect(), simply call:

ioio.disconnect();

You can do this, for example, when your application gets paused, or from a TimerTask, if you want to timeout on a connection attempt. The call is asynchronous. The disconnect process is normally very fast, but if you want to make sure all resources have been freed, you can use:

ioio.waitForDisconnect();

This call will block until the disconnect process completes. You can also use this call to implement a listener that does something upon disconnect.

.